diff --git a/public/app-runtime.js b/public/app-runtime.js index be58118..c169ed9 100644 --- a/public/app-runtime.js +++ b/public/app-runtime.js @@ -4227,7 +4227,9 @@ window.SUN_LEGACY_CATALOG_V175=[{"id":"1","name":"Фуршетный бокс {id:'emerald-circles',name:'Изумрудные круги',desc:'Тёмно-изумрудная презентация с круглыми фото блюд и списком категорий.',thumb:''}, {id:'midnight-checklist',name:'Тёмный чек-лист',desc:'Компактный тёмно-зелёный макет: нумерованное меню по категориям и фотополоса блюд.',thumb:''}, {id:'gourmet-hero',name:'Гастро-витрина',desc:'Крупный фото-хиро в духе лендинга, вкладки категорий и карточки блюд.',thumb:''}, - {id:'diamond-gold',name:'Изумруд и золото',desc:'Тёмно-зелёный дизайн с золотыми акцентами, нумерованной фотосеткой и блоком скидки.',thumb:''} + {id:'diamond-gold',name:'Изумруд и золото',desc:'Тёмно-зелёный дизайн с золотыми акцентами, нумерованной фотосеткой и блоком скидки.',thumb:''}, + {id:'premium-dark',name:'Премиум тёмный',desc:'Строгий тёмный дизайн с золотыми иконками-бейджами дат и гостей, минималистичным списком меню.',thumb:''}, + {id:'premium-emerald',name:'Премиум изумрудный',desc:'Тот же строгий тёмный дизайн с иконками-бейджами, но в изумрудно-зелёной палитре.',thumb:''} ]; const esc=window.SunSafe.escapeHTML; diff --git a/public/core/signature-offer-pdf-v18.js b/public/core/signature-offer-pdf-v18.js index f5f55dd..cc36ec5 100644 --- a/public/core/signature-offer-pdf-v18.js +++ b/public/core/signature-offer-pdf-v18.js @@ -5,7 +5,7 @@ const VERSION='18.1.0'; const RELEASE='20260916-v18-1-0-signature-offer-pdf-polish'; const W=1000,H=1414,SCALE=1.6,M=54; - const SIGNATURE_IDS=['cream-elegance','neon-menu','emerald-circles','midnight-checklist','gourmet-hero','diamond-gold']; + const SIGNATURE_IDS=['cream-elegance','neon-menu','emerald-circles','midnight-checklist','gourmet-hero','diamond-gold','premium-dark','premium-emerald']; const SIGNATURE_SET=new Set(SIGNATURE_IDS); const INNER_THEME={ 'cream-elegance':'light', @@ -13,7 +13,9 @@ 'emerald-circles':'midnight-glass', 'midnight-checklist':'midnight-glass', 'gourmet-hero':'black-gold', - 'diamond-gold':'black-gold' + 'diamond-gold':'black-gold', + 'premium-dark':'black-gold', + 'premium-emerald':'midnight-glass' }; const PALETTES={ 'cream-elegance':{bg:'#faf3e6',paper:'#ffffff',ink:'#22281f',muted:'#726c5f',accent:'#8f8536',accent2:'#4f6a3f',deep:'#274a34',line:'#ecdfc4',foot:'#faf3e6'}, @@ -21,7 +23,9 @@ 'emerald-circles':{bg:'#08181c',paper:'#0d2226',ink:'#eef6f2',muted:'#94aca6',accent:'#c9a24a',accent2:'#2f9e78',deep:'#0a2a26',line:'#1f4642',foot:'#08181c'}, 'midnight-checklist':{bg:'#06170f',paper:'#0b2417',ink:'#eef6ee',muted:'#8fac97',accent:'#dfb957',accent2:'#3f8f5c',deep:'#123822',line:'#1f4a30',foot:'#06170f'}, 'gourmet-hero':{bg:'#0a0a09',paper:'#141311',ink:'#f5f1e8',muted:'#a89f8e',accent:'#d7ac55',accent2:'#8a6a2c',deep:'#1c1a15',line:'#3a352a',foot:'#0a0a09'}, - 'diamond-gold':{bg:'#071510',paper:'#0d251c',ink:'#f0f5ee',muted:'#93ab9c',accent:'#e0b95c',accent2:'#2f9e6f',deep:'#123d29',line:'#204b34',foot:'#071510'} + 'diamond-gold':{bg:'#071510',paper:'#0d251c',ink:'#f0f5ee',muted:'#93ab9c',accent:'#e0b95c',accent2:'#2f9e6f',deep:'#123d29',line:'#204b34',foot:'#071510'}, + 'premium-dark':{bg:'#0a0d12',paper:'#12161d',ink:'#f5f6f8',muted:'#8b93a1',accent:'#e0a545',accent2:'#c9863a',deep:'#171c24',line:'#252b35',foot:'#0a0d12'}, + 'premium-emerald':{bg:'#0a1210',paper:'#121d19',ink:'#f2f8f5',muted:'#8fa79c',accent:'#3fcf8e',accent2:'#2a9d6c',deep:'#17241f',line:'#233830',foot:'#0a1210'} }; // Distinctive Cyrillic-friendly type pairing per polished template (falls back to Georgia/Arial elsewhere). @@ -31,7 +35,9 @@ 'emerald-circles':{display:'"Playfair Display",Georgia,serif',label:'"Montserrat",Arial,sans-serif'}, 'midnight-checklist':{display:'"Unbounded",Arial,sans-serif',label:'"Manrope",Arial,sans-serif'}, 'gourmet-hero':{display:'"Unbounded",Arial,sans-serif',label:'"Manrope",Arial,sans-serif'}, - 'diamond-gold':{display:'"Playfair Display",Georgia,serif',label:'"Montserrat",Arial,sans-serif'} + 'diamond-gold':{display:'"Playfair Display",Georgia,serif',label:'"Montserrat",Arial,sans-serif'}, + 'premium-dark':{display:'"Unbounded",Arial,sans-serif',label:'"Manrope",Arial,sans-serif'}, + 'premium-emerald':{display:'"Unbounded",Arial,sans-serif',label:'"Manrope",Arial,sans-serif'} }; function fontsFor(id){return FONT_STACKS[id]||{display:'Georgia,serif',label:'Arial,sans-serif'}} function ensureFontLink(){ @@ -69,6 +75,14 @@ function eventTitle(s){const event=String(s.event||'Персональное предложение').trim();return String(s.client||'').trim()?'Предложение для '+String(s.client).trim():event} function footer(ctx,p,page,total,brandName='Солнце Кейтеринг',fonts){const lf=fonts?.label||'Arial';line(ctx,M,H-48,W-M,H-48,p.line,1);text(ctx,String(brandName||'Солнце Кейтеринг')+' · предложение клиенту',M,H-34,500,16,{font:`500 10px ${lf}`,color:p.muted,maxLines:1});text(ctx,String(page)+' / '+String(total),W-M,H-34,100,16,{font:`500 10px ${lf}`,color:p.muted,align:'right',maxLines:1})} function iconCircle(ctx,cx,cy,r,glyph,{fill,stroke,glyphColor='#fff',size=20}={}){roundRect(ctx,cx-r,cy-r,r*2,r*2,r,fill,stroke,1.4);text(ctx,glyph,cx,cy-size/2-1,r*2,size+4,{font:`${size}px Arial`,color:glyphColor,align:'center',maxLines:1})} + // Small line-drawn icon badges (calendar/people/gauge/box) for the "premium" templates, so those stat cards use real iconography instead of emoji. + function iconBadge(ctx,x,y,size,p,draw){roundRect(ctx,x,y,size,size,size*0.28,p.deep,p.accent,1.4);ctx.save();ctx.translate(x+size/2,y+size/2);ctx.strokeStyle=p.accent;ctx.fillStyle=p.accent;ctx.lineWidth=Math.max(1.6,size*0.05);ctx.lineCap='round';ctx.lineJoin='round';draw(ctx,size*0.32);ctx.restore()} + function iconCalendar(ctx,r){roundRect(ctx,-r,-r*0.75,r*2,r*1.65,r*0.22,null,ctx.strokeStyle,ctx.lineWidth);ctx.beginPath();ctx.moveTo(-r,-r*0.3);ctx.lineTo(r,-r*0.3);ctx.stroke();ctx.beginPath();ctx.moveTo(-r*0.5,-r*1.05);ctx.lineTo(-r*0.5,-r*0.55);ctx.stroke();ctx.beginPath();ctx.moveTo(r*0.5,-r*1.05);ctx.lineTo(r*0.5,-r*0.55);ctx.stroke()} + function iconPeople(ctx,r){ctx.beginPath();ctx.arc(0,-r*0.4,r*0.4,0,Math.PI*2);ctx.stroke();ctx.beginPath();ctx.arc(0,r*0.75,r*0.82,Math.PI,0,true);ctx.stroke()} + function iconGauge(ctx,r){ctx.beginPath();ctx.arc(0,r*0.15,r*0.85,Math.PI,0);ctx.stroke();ctx.beginPath();ctx.moveTo(0,r*0.15);ctx.lineTo(r*0.48,-r*0.32);ctx.stroke();ctx.beginPath();ctx.arc(0,r*0.15,r*0.1,0,Math.PI*2);ctx.fill()} + function iconBox(ctx,r){roundRect(ctx,-r,-r*0.75,r*2,r*1.55,r*0.16,null,ctx.strokeStyle,ctx.lineWidth);ctx.beginPath();ctx.moveTo(-r,-r*0.05);ctx.lineTo(r,-r*0.05);ctx.stroke();ctx.beginPath();ctx.moveTo(0,-r*0.75);ctx.lineTo(0,r*0.8);ctx.stroke()} + function statBadgeRow(ctx,p,f,x,y,w,h,cards){const gap=14,cw=(w-gap*(cards.length-1))/cards.length;const bs=Math.min(52,h*0.42);cards.forEach(([draw,value,label],i)=>{const xx=x+i*(cw+gap);roundRect(ctx,xx,y,cw,h,20,p.paper,p.line,1);iconBadge(ctx,xx+18,y+18,bs,p,draw);text(ctx,value,xx+18+bs+10,y+18+bs/2-12,cw-18-bs-10-12,24,{font:`700 16px ${f.display}`,color:'#fff',maxLines:1});text(ctx,label,xx+18,y+h-30,cw-36,16,{font:`500 12px ${f.label}`,color:p.muted,maxLines:1})})} + function bulletList(ctx,p,f,x,y,w,lineH,items,color){let yy=y;items.forEach(t=>{ctx.save();ctx.fillStyle=p.accent;ctx.beginPath();ctx.arc(x+4,yy+9,4,0,Math.PI*2);ctx.fill();ctx.restore();const used=text(ctx,t,x+20,yy,w-20,18,{font:`500 14px ${f.label}`,color:color||p.ink,maxLines:2});yy+=Math.max(lineH,used+6)});return yy-y} function factChips(ctx,s,p,x,y,w,{dark=true,fonts}={}){const lf=fonts?.label||'Arial';const facts=[];if(s.date)facts.push(dateText(s.date));if(s.guests)facts.push(String(s.guests)+' '+plural(s.guests,'гость','гостя','гостей'));if(s.time)facts.push('Доставка '+String(s.time));const gap=8,cw=(w-gap*Math.max(0,facts.length-1))/Math.max(1,facts.length);facts.forEach((f,i)=>{const xx=x+i*(cw+gap);roundRect(ctx,xx,y,cw,44,13,dark?'rgba(255,255,255,.06)':p.paper,dark?'rgba(255,255,255,.2)':p.line);text(ctx,f,xx+cw/2,y+14,cw-14,17,{font:`600 12px ${lf}`,color:dark?'#f4f1e6':p.ink,align:'center',maxLines:1})})} function menuList(ctx,s,p,x,y,w,rowH,count,{dark=true,numbered=true,fonts}={}){const df=fonts?.display||'Georgia',lf=fonts?.label||'Arial';const items=(s.items||[]).slice(0,count),gap=8;items.forEach((item,i)=>{const yy=y+i*(rowH+gap);roundRect(ctx,x,yy,w,rowH,13,dark?'rgba(255,255,255,.05)':p.paper,dark?'rgba(255,255,255,.14)':p.line);const badgeX=x+14;if(numbered){roundRect(ctx,badgeX,yy+rowH/2-13,26,26,13,p.accent,null);text(ctx,String(i+1),badgeX+13,yy+rowH/2-9,26,18,{font:`700 12px ${lf}`,color:p.deep,align:'center',maxLines:1})}const textX=numbered?badgeX+38:x+16;text(ctx,item.name||'Позиция меню',textX,yy+10,w-(textX-x)-70,20,{font:`600 14px ${df}`,color:dark?'#fff':p.ink,maxLines:1});const meta=[item.weight?String(item.weight):'',].filter(Boolean).join(' · ');if(meta)text(ctx,meta,textX,yy+rowH-24,w-(textX-x)-70,16,{font:`500 11px ${lf}`,color:p.muted,maxLines:1});text(ctx,'× '+Math.round(Number(item.qty||1)),x+w-16,yy+rowH/2-9,50,18,{font:`700 12px ${lf}`,color:p.accent,align:'right',maxLines:1})});return items.length*(rowH+gap)} function photoGridSquare(ctx,s,p,x,y,w,h,cols,rows,{numbered=true,fonts}={}){const lf=fonts?.label||'Arial';const items=(s.items||[]).slice(0,cols*rows);const gap=7,cw=(w-gap*(cols-1))/cols,ch=(h-gap*(rows-1))/rows;return (async()=>{const imgs=await Promise.all(items.map(it=>loadImage(it.photoData||'')));imgs.forEach((img,i)=>{const col=i%cols,row=Math.floor(i/cols),xx=x+col*(cw+gap),yy=y+row*(ch+gap);roundRect(ctx,xx,yy,cw,ch,10,p.deep,null);if(img)coverImage(ctx,img,xx,yy,cw,ch,10);if(numbered){roundRect(ctx,xx+6,yy+6,22,22,11,'rgba(6,10,8,.72)',null);text(ctx,String(i+1),xx+17,yy+10,22,16,{font:`700 10px ${lf}`,color:'#fff',align:'center',maxLines:1})}})})()} @@ -162,6 +176,20 @@ statCards(ctx,s,p,M,900,306,90,[[Math.round(classicBoxCount(s))||0,'КОРОБОК'],[(s.items||[]).length,'ПОЗИЦИЙ']],{dark:true,fonts:f});priceBand(ctx,s,p,376,900,306,90,{dark:true,fonts:f}); const dgx=698,dgy=900;roundRect(ctx,dgx,dgy,248,90,16,'rgba(255,255,255,.04)',p.line);ctx.save();ctx.translate(dgx+124,dgy+45);ctx.rotate(Math.PI/4);ctx.fillStyle=p.accent;ctx.fillRect(-16,-16,32,32);ctx.restore();text(ctx,'СКИДКА ВКЛЮЧЕНА',dgx+124,dgy+70,248,14,{font:`700 9px ${f.label}`,color:p.muted,align:'center',maxLines:1}); checklistCard(ctx,p,M,1010,470,170,'ДОСТАВКА И КОНТРОЛЬ КАЧЕСТВА',CHECK_LINES,{dark:true,fonts:f});addonRow(ctx,p,540,1010,406,170,ADDON_LINES.concat(['Посуда','Мебель']),{dark:true,fonts:f}); + }else if(id==='premium-dark'||id==='premium-emerald'){ + logoOrBrand(ctx,logo,p,{x:M,y:44,dark:true,fonts:f},s.brandName); + text(ctx,'ПЕРСОНАЛЬНОЕ ПРЕДЛОЖЕНИЕ',M,140,500,16,{font:`700 11px ${f.label}`,color:p.accent,maxLines:1}); + text(ctx,title,M,164,W-2*M,40,{font:`700 32px ${f.display}`,color:'#fff',maxLines:2}); + bulletList(ctx,p,f,M,256,W-2*M,30,CHECK_LINES,'#dfe3e8'); + if(hero)coverImage(ctx,hero,M,396,W-2*M,230,26); + statBadgeRow(ctx,p,f,M,650,W-2*M,104,[[iconCalendar,dateText(s.date)||'Уточняется','Дата мероприятия'],[iconPeople,s.guests?String(s.guests):'—','Количество гостей'],[iconBox,String(Math.round(classicBoxCount(s))||0),'Коробок в заказе']]); + text(ctx,'МЕНЮ',W/2,786,W,26,{font:`700 22px ${f.display}`,color:'#fff',align:'center',maxLines:1}); + line(ctx,M,812,410,812,p.line,1);line(ctx,590,812,W-M,812,p.line,1); + await photoGridSquare(ctx,s,p,M,846,W-2*M,272,3,2,{numbered:true,fonts:f}); + statCards(ctx,s,p,M,1138,565,95,[[Math.round(classicBoxCount(s))||0,'КОРОБОК'],[(s.items||[]).length,'ПОЗИЦИЙ']],{dark:true,fonts:f}); + priceBand(ctx,s,p,640,1138,306,95,{dark:true,fonts:f}); + checklistCard(ctx,p,M,1253,470,113,'ВСЁ ПОД КОНТРОЛЕМ',CHECK_LINES.slice(0,2),{dark:true,fonts:f}); + addonRow(ctx,p,540,1253,406,113,ADDON_LINES,{dark:true,fonts:f}); } canvas.dataset.sunSignatureTemplate=id;canvas.dataset.sunSignatureCover='1';return canvas; } @@ -241,13 +269,15 @@ } function installPreviewStyles(){if(document.getElementById('sunSignatureOfferPreviewV18'))return;const style=document.createElement('style');style.id='sunSignatureOfferPreviewV18';style.textContent=` - .sun-offer-template-mini[data-template-mini="cream-elegance"] i,.sun-offer-template-mini[data-template-mini="neon-menu"] i,.sun-offer-template-mini[data-template-mini="emerald-circles"] i,.sun-offer-template-mini[data-template-mini="midnight-checklist"] i,.sun-offer-template-mini[data-template-mini="gourmet-hero"] i,.sun-offer-template-mini[data-template-mini="diamond-gold"] i{display:none!important} + .sun-offer-template-mini[data-template-mini="cream-elegance"] i,.sun-offer-template-mini[data-template-mini="neon-menu"] i,.sun-offer-template-mini[data-template-mini="emerald-circles"] i,.sun-offer-template-mini[data-template-mini="midnight-checklist"] i,.sun-offer-template-mini[data-template-mini="gourmet-hero"] i,.sun-offer-template-mini[data-template-mini="diamond-gold"] i,.sun-offer-template-mini[data-template-mini="premium-dark"] i,.sun-offer-template-mini[data-template-mini="premium-emerald"] i{display:none!important} .sun-offer-template-mini[data-template-mini="cream-elegance"]{background:radial-gradient(circle at 78% 30%,#fff 0 18%,#8f8536 19% 21%,transparent 22%),linear-gradient(#fdf7ea,#f2e3bf)!important} .sun-offer-template-mini[data-template-mini="neon-menu"]{background:linear-gradient(90deg,rgba(57,226,122,.35),transparent 45%),linear-gradient(135deg,#0d1210,#070908)!important;border-color:#1f4430!important} .sun-offer-template-mini[data-template-mini="emerald-circles"]{background:radial-gradient(circle at 70% 55%,#c9a24a 0 6%,transparent 7%),radial-gradient(circle at 85% 55%,#c9a24a 0 6%,transparent 7%),linear-gradient(135deg,#0d2226,#08181c)!important;border-color:#1f4642!important} .sun-offer-template-mini[data-template-mini="midnight-checklist"]{background:repeating-linear-gradient(0deg,#0b2417 0 11%,#123822 11% 12%),#06170f!important;border-color:#1f4a30!important} .sun-offer-template-mini[data-template-mini="gourmet-hero"]{background:linear-gradient(90deg,#141311 0 55%,#3a352a 55% 58%,#0a0a09 58%)!important;border-color:#3a352a!important} .sun-offer-template-mini[data-template-mini="diamond-gold"]{background:radial-gradient(circle at 75% 35%,#e0b95c 0 5%,transparent 6%),linear-gradient(135deg,#123d29,#071510)!important;border-color:#204b34!important} + .sun-offer-template-mini[data-template-mini="premium-dark"]{background:radial-gradient(circle at 18% 15%,rgba(224,165,69,.35),transparent 40%),linear-gradient(160deg,#12161d,#0a0d12)!important;border-color:#252b35!important} + .sun-offer-template-mini[data-template-mini="premium-emerald"]{background:radial-gradient(circle at 18% 15%,rgba(63,207,142,.35),transparent 40%),linear-gradient(160deg,#121d19,#0a1210)!important;border-color:#233830!important} `;document.head.appendChild(style)} if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',installPreviewStyles,{once:true});else installPreviewStyles();