From 8dddf0fa25514145a012d640647d901cfa06fae1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cau=C3=AA=20Faleiros?= Date: Tue, 29 Sep 2026 16:36:41 -0300 Subject: [PATCH] feat: redesign the Montagem page, with thumbnails, check chips and a DPI price scale MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The product page is rebuilt around mockup 1. The two ways to send are cards under the title; the PNG/CDR route choice is gone (it never changed the price, and the picker now takes every allowed format). Each file card has a thumbnail, its size, check chips with a plain sentence for any problem, a "Ver detalhes da conferência" link and a copies stepper; a CDR file says "Conferência manual · preço cheio" and asks for the length. The buy box shows the price scale in DPI with the customer's step, the metre and 10 cm length, the total and what the resolution saved, and "Sai em N partes" only above 20 m. Folha já montada gets "Ampliar" instead of zoom. Pricing, grade and checks are unchanged. Fixes on top: the card thumbnail is a small image made once, not the full preview re-parsed on every repaint; sizes from 1 GB up read in GB; a failed upload is shown with "Tentar de novo" instead of retrying silently on every cart change. The browser suites wait for the product and the reloaded page instead of racing them, and the artwork suite delays imagemDaArte, which the packing now uses, fixing the CI failure of f4aacb5. Co-Authored-By: Claude Opus 5.5 --- tests/artwork_browser_test.mjs | 12 ++- tests/browser_test.mjs | 3 +- web/checkout.js | 33 ++++++- web/index.html | 88 ++++++------------ web/site-cart.js | 2 +- web/site-compra.js | 23 +++-- web/site-config.js | 26 ++---- web/site-flow.js | 35 ++------ web/site-modes.js | 16 ++-- web/site-packing.js | 3 + web/site-pdf.js | 160 +++++++++++++++++++-------------- web/site-upload.js | 20 +---- web/site-v2.css | 154 +++++++++++++++++++++++++------ 13 files changed, 335 insertions(+), 240 deletions(-) diff --git a/tests/artwork_browser_test.mjs b/tests/artwork_browser_test.mjs index dbcfc55..7dd952f 100644 --- a/tests/artwork_browser_test.mjs +++ b/tests/artwork_browser_test.mjs @@ -115,7 +115,7 @@ try{ await call('Runtime.enable');await call('Page.enable'); await call('Emulation.setDeviceMetricsOverride',{width:1440,height:1100,deviceScaleFactor:1,mobile:false}); await call('Page.navigate',{url:`http://127.0.0.1:${server.address().port}/`}); - await waitFor(()=>evaluate(`typeof sel==='function' && typeof AUTO!=='undefined'`),'Site scripts'); + await waitFor(()=>evaluate(`typeof sel==='function' && typeof pintaEntrega==='function'`),'Site scripts'); // Observe the actual engine, without replacing its placement or rendering. await evaluate(`(()=>{ const original=encaixar; @@ -149,6 +149,9 @@ try{ // Navigation links must reach the chooser, never preselect a product. assert.equal(await evaluate(`document.querySelectorAll('[data-modo-cta]').length`),0); await click('[data-modo="file"]'); + // Opening a product paints on the next frame; on a busy runner the check + // must wait for it rather than race it. + await waitFor(()=>evaluate(`!$('tipoEnvio').hidden`),'by-metre product open'); // By-metre opens declaring a mounted sheet; switching is explicit and priced. assert.deepEqual(await evaluate(`({shown:!$('tipoEnvio').hidden, on:[...document.querySelectorAll('#tipoEnvio .cam.on')].map(b=>b.dataset.tipo)})`), @@ -293,13 +296,14 @@ try{ await fill('[data-cm]',10);await fill('[data-q]',4);await packed(4); } // An older image load must not overwrite a newer edit, even before debounce. - await evaluate(`(()=>{window.realLoad=carregarImagem;window.delayed=[]; - carregarImagem=f=>new Promise(resolve=>delayed.push(()=>realLoad(f).then(resolve))); + // The packing loads each artwork's image through imagemDaArte. + await evaluate(`(()=>{window.realLoad=imagemDaArte;window.delayed=[]; + imagemDaArte=a=>new Promise(resolve=>delayed.push(()=>realLoad(a).then(resolve))); })()`); await fill('[data-q]',5); await waitFor(()=>evaluate('delayed.length===1'),'delayed preview'); await fill('[data-q]',7); - await evaluate(`carregarImagem=realLoad;delayed[0]()`); + await evaluate(`imagemDaArte=realLoad;delayed[0]()`); await packed(7); const timeoutCleanup=await evaluate(`(async()=>{ const realLoader=carregarPdfJs, realTimer=setTimeout, realWorker=temWorker; diff --git a/tests/browser_test.mjs b/tests/browser_test.mjs index 94df84a..5ea3f5e 100644 --- a/tests/browser_test.mjs +++ b/tests/browser_test.mjs @@ -62,12 +62,13 @@ try{ await site.call('Page.setBypassCSP',{enabled:false}); await site.call('Page.reload'); await waitFor(()=>site.eval('typeof window.dtfCheckout === "function"'),'reload after security probe'); + // The check above can still pass on the page being replaced; wait for the new one's cards. + await waitFor(()=>site.eval(`!!document.querySelector('[data-modo="file"]') && document.readyState==='complete'`),'product cards after reload'); await site.click('[data-modo="file"]'); // Each product has its own page; the home's parts are not on it. assert.deepEqual(await site.eval(`({path:location.pathname,page:document.documentElement.dataset.rota, cards:getComputedStyle($('cards')).display,cart:getComputedStyle($('carr')).display})`), {path:'/arquivo-por-metro',page:'produto',cards:'none',cart:'none'}); - await site.click('[data-cam="tabela"]'); const root=await site.call('DOM.getDocument'); const input=await site.call('DOM.querySelector',{nodeId:root.root.nodeId,selector:'#inp'}); await site.call('DOM.setFileInputFiles',{nodeId:input.nodeId,files:[resolve('tests/fixtures/local-test.cdr')]}); diff --git a/web/checkout.js b/web/checkout.js index 011c10b..eb80270 100644 --- a/web/checkout.js +++ b/web/checkout.js @@ -112,12 +112,21 @@ return window.dtfUpload(file,{api,scope:session.cart_scope,progress:()=>{}, onBytes:n=>{e.sent=n;pintaEnvio();}}); })(); - e.promise.then(()=>{e.done=true;pintaEnvio();}, - error=>{e.failed=error;envios.delete(k);pintaEnvio();}); + e.promise.then(()=>{e.done=true;falhas.delete(k);pintaEnvio();}, + error=>{envios.delete(k);falhas.set(k,{file,error});pintaEnvio();}); envios.set(k,e); } return e.promise; } + // A failed upload is shown and waits for the customer, never retried behind + // their back: a file the check refused would fail again on every change. + const falhas=new Map(); + function tentaDeNovo() { + const arquivos=[...falhas.values()].map(f=>f.file); + falhas.clear(); + arquivos.forEach(f=>enviar(f).catch(()=>{})); + pintaEnvio(); + } const arquivosDoCarrinho=()=>[...pedido,...(busy&&itemAtual?[itemAtual]:[])].flatMap(it=>it.localFiles||[]); const gb=n=>(n/1073741824).toLocaleString('pt-BR',{maximumFractionDigits:1})+' GB'; const mb=n=>n>=1073741824 ? gb(n) : Math.round(n/1048576)+' MB'; @@ -149,6 +158,20 @@ function pintaEnvio() { const e=estadoEnvio(), texto=textoEnvio(e); const el=document.getElementById('envioArq'); + const falhou=arquivosDoCarrinho().map(f=>falhas.get(chaveArquivo(f))).filter(Boolean); + const topo=document.getElementById('cartEnvio'); + if (falhou.length) { + if (el) { + el.replaceChildren(document.createTextNode('Não foi possível enviar '+falhou[0].file.name+': '+ + (falhou[0].error?.message||'erro no envio').replace(/\.$/,'')+(falhou.length>1?' (e mais '+(falhou.length-1)+')':'')+'. ')); + const b=document.createElement('button'); b.type='button'; b.className='envioDeNovo'; b.textContent='Tentar de novo'; + b.onclick=tentaDeNovo; el.append(b); + el.classList.remove('ok'); el.classList.add('erro'); + } + if (topo) topo.textContent='· falha no envio'; + return; + } + if (el) el.classList.remove('erro'); if (el) { el.replaceChildren(); if (e && e.fase!=='pronto') { @@ -160,7 +183,6 @@ el.classList.toggle('ok', e?.fase==='pronto'); } // Visible on every page while it runs. - const topo=document.getElementById('cartEnvio'); if (topo) topo.textContent = !e || e.fase==='pronto' ? '' : e.fase==='verificando' ? '· verificando' : '· enviando '+e.pct+'%'; if (busy && texto) { message(texto); @@ -173,7 +195,10 @@ if (e && e.fase==='enviando') { event.preventDefault(); event.returnValue=''; } }); // Only what is in the cart: the item on the product page may still change. - window.addEventListener('dtf-cart-changed',()=>{ arquivosDoCarrinho().forEach(f=>{ enviar(f).catch(()=>{}); }); pintaEnvio(); }); + window.addEventListener('dtf-cart-changed',()=>{ + arquivosDoCarrinho().forEach(f=>{ if(!falhas.has(chaveArquivo(f))) enviar(f).catch(()=>{}); }); + pintaEnvio(); + }); async function upload(file) { return enviar(file); } diff --git a/web/index.html b/web/index.html index 51c37bb..b2b76bc 100644 --- a/web/index.html +++ b/web/index.html @@ -234,8 +234,6 @@ h1 em{font-style:normal;color:var(--laranja)} font-family:"Inter",sans-serif;font-weight:700} /* upload */ -/* o cliente escolhe o caminho antes de subir · a declaração orienta, - mas quem decide o preço é o arquivo que chegar */ .caminhos{display:grid;grid-template-columns:1fr 1fr;gap:9px;margin-bottom:13px} @media(max-width:620px){.caminhos{grid-template-columns:1fr}} .caminhos>*{min-width:0} @@ -254,7 +252,6 @@ h1 em{font-style:normal;color:var(--laranja)} .cam span{display:block;font-size:10.5px;color:var(--fraco);line-height:1.45} .cam em{display:block;margin-top:6px;font-style:normal;font-family:"Inter",sans-serif; font-weight:700;font-size:12px;color:var(--verde-ml);line-height:1.3} -.cam em.cheio{color:var(--vermelho)} .trocouCam{margin-top:-4px;margin-bottom:11px;padding:10px 12px;border-radius:9px; background:#FFF6E8;border:1px solid #F0D9AE;font-size:11.5px;color:#7A5A16;line-height:1.5} .trocouCam b{color:#B07A18;font-family:"Inter",sans-serif;font-weight:700} @@ -301,12 +298,6 @@ h1 em{font-style:normal;color:var(--laranja)} /* repetição do FILE */ .rep{background:var(--cinza);border-radius:9px;padding:12px 14px;margin-top:8px} -.somaF{margin-top:10px;padding:11px 13px;border-radius:9px;background:#F1FBF5; - border:1px solid #BFE6CE;display:flex;flex-wrap:wrap;align-items:baseline;gap:8px} -.somaF span{font-size:11.5px;color:#2A6B45} -.somaF b{font-family:"Inter",sans-serif;font-weight:700;font-size:15px;color:#1F5C3A; - margin-left:auto} -.somaF em{flex-basis:100%;font-style:normal;font-size:10.5px;color:#4A7A5E} .rep .l1{display:flex;justify-content:space-between;gap:10px;align-items:center;margin-bottom:9px} .rep .l1 b{font-weight:500;font-size:12.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} .rep .l1 button{border:0;background:none;color:var(--fraco);cursor:pointer;font-size:15px;flex:none} @@ -317,33 +308,10 @@ h1 em{font-style:normal;color:var(--laranja)} .progF{margin:9px 0 4px;padding:9px 11px;border-radius:7px;background:#FFF6E8; border:1px solid #F0D9AE;font-size:11px;color:#7A5A16;line-height:1.5} .progF b{font-family:"Inter",sans-serif;font-weight:700;color:#B07A18} -.rep .cps{display:grid;grid-template-columns:120px 1fr;gap:10px;align-items:end} .rep label{display:block;font-size:10px;color:var(--fraco);margin-bottom:3px} .rep input{width:100%;padding:7px 9px;border:1px solid var(--linha);border-radius:6px; font-family:inherit;font-size:13px;background:#fff;color:var(--tx)} .rep input:focus{outline:none;border-color:var(--laranja)} -.rep .conta{font-size:11.5px;color:var(--fraco);line-height:1.4} -.rep .conta b{color:var(--tx);font-family:"Inter",sans-serif} -.med{background:#fff;border:1px solid var(--linha);border-radius:8px;padding:10px 12px;margin-top:9px} -.med b{display:block;font-family:"Inter",sans-serif;font-size:15px;font-weight:700;color:var(--tx)} -.med span{display:block;font-size:11px;color:var(--fraco);margin-top:2px} -.med em{display:block;font-style:normal;font-size:11.5px;color:#B07A18;margin-top:7px;line-height:1.45} -.med.alerta{border-color:#E8A796;background:#FFF3F0} -.med.alerta b{color:#8C3B22} -.med.alerta em{color:#8C3B22} -.med.pede{border-color:var(--laranja);background:#FFFAF2} -.med.pede b{font-size:12.5px;color:#B07A18} -.conf{margin-top:9px;padding:9px 11px;border-radius:7px;background:#F1FBF5; - border:1px solid #BFE6CE;line-height:1.5} -.conf b{display:block;font-family:"Inter",sans-serif;font-size:11.5px;color:#1F5C3A; - margin-bottom:3px} -.conf span{display:block;font-size:10.5px;color:#2A6B45} -.med .troca{margin-top:9px;padding:9px 11px;border-radius:7px;background:#F1FBF5; - border:1px solid #BFE6CE;font-size:11.5px;color:#1F5C3A;line-height:1.5} -.med .troca b{display:inline;font-size:11.5px;color:#1F5C3A;font-weight:700} -.med input{width:100%;margin-top:8px;padding:8px 10px;border:1px solid var(--linha); - border-radius:6px;font-family:inherit;font-size:13px;background:#fff;color:var(--tx)} -.med input:focus{outline:none;border-color:var(--laranja)} /* fila de artes ao lado da montagem */ .foco2{display:grid;grid-template-columns:minmax(340px,1fr) 320px;gap:20px; @@ -929,55 +897,39 @@ footer a:hover{color:var(--laranja2)}

—

- -

- -
- - -
+ +
↑
Arraste aqui Até 5 GB por arquivo. ou escolher no computador + Adicionar outra folha ou arraste aqui + Tem CDR, AI, PSD ou TIFF? Pode mandar também. + Alguém abre na mão e o metro sai pelo preço cheio.
- -
-

Revisão de 5 pontos e reencaixe grátis

+

Revisamos e reencaixamos antes de imprimir, sem custo.

+ +
Sua folha +
+
+
diff --git a/web/site-cart.js b/web/site-cart.js index accb66a..bdef20a 100644 --- a/web/site-cart.js +++ b/web/site-cart.js @@ -120,7 +120,7 @@ function carrinho(){ previa(); if(nota<90){ const piso=pisoEscada(), ganho=(base-piso)*cob; - if(ganho>0.5) qm('Dá para chegar ao melhor preço. Corrigindo os pontos e chegando a 90, '+ + if(ganho>0.5) qm('Dá para pagar menos. Com a arte em 300 DPI, '+ 'o metro cai para '+rs(piso)+' — são '+rs(ganho)+' a menos neste pedido.','var(--verde)'); } } diff --git a/web/site-compra.js b/web/site-compra.js index fd2154a..c82857f 100644 --- a/web/site-compra.js +++ b/web/site-compra.js @@ -1,4 +1,4 @@ -/* Site DTF — the product page's buy box: grade, price per metre, billed length, +/* Site DTF — the product page's buy box: price ladder, price per metre, billed length, total and the add-to-cart button, beside the live sheet. It shows the item the other site-*.js files already priced (itemAtual) and never computes a price of its own, so the box and the cart always agree. */ @@ -10,18 +10,29 @@ add.disabled=!it || !itemPodeEnviar(it); if(!it) return; const semNota=!it.nota; - $('cNota').textContent = semNota ? 'sem nota' : it.nota; - $('cNotaBar').style.width=(semNota?0:it.nota)+'%'; - $('cNotaBar').className = semNota ? '' : it.nota>=85 ? 'ok' : it.nota>=50 ? 'av' : 'er'; - $('cTabela').textContent = TABELA[it.modo]-it.unit>0.001 ? rs(TABELA[it.modo]) : ''; + // The price ladder in resolution: nota = DPI ÷ 3, so 90 is 270 DPI. + const faixas=FAIXAS[it.modo], ativa=faixas.findIndex(([min])=>it.nota>=min); + $('cEscada').innerHTML=faixas.map(([min,v],i)=> + ''+ + (min? min*3+'+'+(i? '' : ' DPI') : semNota? 'cheio' : 'menos')+''+ + ''+rs(v).slice(3)+'').join(''); + const analisadas=ehFolha(it.modo) && folhas.length && folhas.every(x=>x.an); + $('cMetroLbl').textContent = semNota ? 'Metro · preço cheio' + : analisadas && folhas.every(x=>x.an.vetor) ? 'Metro · arte vetorial' + : analisadas ? 'Metro · '+Math.min(...folhas.map(x=>x.an.dpi))+' DPI' + : 'Metro'; $('cMetro').textContent=rs(it.unit); $('cMetragem').textContent=fmtM(it.cob)+' m'; + const economia=(TABELA[it.modo]-it.unit)*it.cob; + $('cEco').textContent = economia>0.005 ? rs(economia)+' a menos pela resolução da arte' : ''; + const partes=ehFolha(it.modo) ? Math.ceil(it.metros/20) : 1; + $('cPartes').textContent = partes>1 ? ' Sai em '+partes+' partes de até 20 m.' : ''; const sobraCm=Math.round((it.cob-it.metros)*100); $('cObs').textContent = it.cob===MINIMO_M && it.metros0 ? fmtM(it.metros)+' m de folha, arredondado a cada 10 cm.' : ''; + : ''; $('cTotal').textContent=rs(it.total); } add.addEventListener('click',()=>adicionaAoCarrinho()); diff --git a/web/site-config.js b/web/site-config.js index 815b6ae..b1f5d21 100644 --- a/web/site-config.js +++ b/web/site-config.js @@ -5,28 +5,19 @@ const $=id=>document.getElementById(id); const rs=v=>'R$ '+v.toFixed(2).replace('.',','); -const fmt=b=>b<1048576?(b/1024).toFixed(0)+' KB':(b/1048576).toFixed(1).replace('.',',')+' MB'; +const fmt=b=>b<1048576?(b/1024).toFixed(0)+' KB' + :b<1073741824?(b/1048576).toFixed(1).replace('.',',')+' MB':(b/1073741824).toFixed(1).replace('.',',')+' GB'; // ── modos const MODOS={ - file: {tit:'Arquivo por metro', lg:'DTF têxtil · 57 cm', larg:57, - preco:'R$ 14,90 a R$ 19,90 /m conforme a nota', multi:true, folha:true, - sub:'Sua folha montada. Revisamos, corrigimos e reencaixamos antes de imprimir.', - zt:'Arraste suas folhas montadas', - zs:'uma ou várias · PNG, JPG, TIFF ou PDF · PSD, AI e CDR passam por tratamento'}, - avulsa:{tit:'Artes avulsas', lg:'DTF têxtil · 57 cm', larg:57, - preco:'R$ 24,90 a R$ 29,90 /m conforme a nota', multi:true, - sub:'Cada arte num arquivo. Montamos a folha com o melhor encaixe.', + file: {tit:'Arquivo por metro', lg:'DTF têxtil · 57 cm', larg:57, multi:true, folha:true, + zt:'Arraste sua folha montada aqui', zs:'PNG, JPG ou PDF · 57 cm de largura'}, + avulsa:{tit:'Artes avulsas', lg:'DTF têxtil · 57 cm', larg:57, multi:true, zt:'Arraste suas artes aqui', zs:'PNG ou JPG com fundo transparente · informe a largura de cada uma'}, - uvfile:{tit:'Arquivo por metro · UV', lg:'Adesivo UV · 28,5 cm', larg:28.5, - preco:'R$ 69,90 a R$ 85,90 /m conforme a nota', multi:true, folha:true, - sub:'Sua folha de UV montada. Revisamos, corrigimos e reencaixamos antes de imprimir.', - zt:'Arraste suas folhas de UV', - zs:'uma ou várias · PNG, JPG, TIFF ou PDF · PSD, AI e CDR passam por tratamento'}, - uv: {tit:'Artes avulsas · UV', lg:'Adesivo UV · 28,5 cm', larg:28.5, - preco:'R$ 83,90 a R$ 99,90 /m conforme a nota', multi:true, - sub:'Cada arte de UV num arquivo. Montamos a folha com o melhor encaixe.', + uvfile:{tit:'Arquivo por metro · UV', lg:'Adesivo UV · 28,5 cm', larg:28.5, multi:true, folha:true, + zt:'Arraste sua folha de UV aqui', zs:'PNG, JPG ou PDF · 28,5 cm de largura'}, + uv: {tit:'Artes avulsas · UV', lg:'Adesivo UV · 28,5 cm', larg:28.5, multi:true, zt:'Arraste suas artes de UV', zs:'PNG ou JPG com fundo transparente · informe a largura de cada arte'} }; @@ -77,7 +68,6 @@ let pedido=[]; // itens já fechados · o pagamento // ao que a expedição já recebe hoje, sem criar processo novo. let entrega={tipo:'retira', cep:'', valor:0, cotado:true, end:{}}; let cliente={cnpj:'', zap:'', mail:''}; -let caminho='auto'; // o que o cliente diz que vai mandar // CNPJ com os dois dígitos verificadores · máscara sem conta não vale nada function cnpjOk(v){ diff --git a/web/site-flow.js b/web/site-flow.js index 6140cb1..532468a 100644 --- a/web/site-flow.js +++ b/web/site-flow.js @@ -1,4 +1,4 @@ -/* Site DTF — Carousel, path selector, delivery choice and input masks. +/* Site DTF — Carousel, delivery choice and input masks. Extracted verbatim from the single inline script in web/index.html. Loaded as classic scripts in the order listed there: they share one global scope and run top to bottom, exactly as the original did. */ @@ -73,31 +73,6 @@ $('pVolta').addEventListener('click',()=>{ $('cPro').addEventListener('click',()=>ir(atual()+1)); })(); -// A declaração de formato só orienta: filtra o seletor e mostra o preço esperado. -// Se o arquivo que chegar contrariar, o arquivo ganha e o site avisa. -const AUTO=/[.](png|jpe?g|webp|pdf)$/i; -function pintaCaminhos(){ - if(!$('caminhos')) return; - const ehF=modo&&ehFolha(); - $('caminhos').style.display = ehF? '' : 'none'; - if(!ehF) return; - document.querySelectorAll('#caminhos .cam').forEach(b=>b.classList.toggle('on', b.dataset.cam===caminho)); - $('camA').textContent='a partir de '+rs(pisoEscada()); - $('camB').textContent=rs(TABELA[modo])+' fixo'; - $('inp').accept = caminho==='auto' ? '.png,.jpg,.jpeg,.pdf' - : '.tif,.tiff,.psd,.psb,.ai,.cdr'; - $('zSub').textContent = caminho==='auto' - ? 'PNG, JPG ou PDF · conferência automática, nota na tela' - : 'CDR, AI, PSD ou TIFF · sem conferência, metro pela tabela'; -} -document.querySelectorAll('#caminhos .cam').forEach(b=>b.addEventListener('click',()=>{ - caminho=b.dataset.cam; avisoCam(''); pintaCaminhos(); -})); -function avisoCam(txt){ - const el=$('trocouCam'); if(!el) return; - el.innerHTML=txt; el.style.display = txt? '' : 'none'; -} - function pintaEntrega(){ document.querySelectorAll('.opE').forEach(b=> b.classList.toggle('on', b.dataset.ent===entrega.tipo)); @@ -150,6 +125,14 @@ $('zMenos').addEventListener('click',()=>{ if(zoomI>0){ zoomI--; pintaZoom(); previaAoVivo(); } }); pintaZoom(); +// A ready sheet has nothing to zoom: "Ampliar" shows the same preview bigger. +$('bAmpliar').addEventListener('click',()=>{ + const previas=$('vArea').querySelector('.folhaPrevias'); if(!previas) return; + $('ampliaArea').replaceChildren(previas.cloneNode(true)); + $('ampliaDlg').showModal(); +}); +$('ampliaFecha').addEventListener('click',()=>$('ampliaDlg').close()); +$('ampliaDlg').addEventListener('click',e=>{ if(e.target===$('ampliaDlg')) $('ampliaDlg').close(); }); document.querySelectorAll('.opE').forEach(b=>b.addEventListener('click',()=>{ entrega.tipo=b.dataset.ent; diff --git a/web/site-modes.js b/web/site-modes.js index 4173f42..7eca571 100644 --- a/web/site-modes.js +++ b/web/site-modes.js @@ -15,7 +15,7 @@ function abrir(m){ avisoTipo(''); pintaModo(); $('lista').innerHTML=''; $('rA').style.display='none'; recusa([]); - recemChegada=null; caminho='auto'; avisoCam(''); pintaCaminhos(); + recemChegada=null; $('vMt').textContent='—'; previaAoVivo(); agendaAvaliacao(); limpaPaineis(); // o carrinho só some se o pedido estiver vazio vaiPara(PAGINAS[m]); @@ -25,10 +25,13 @@ function pintaModo(){ const c=MODOS[m]; $('cards').style.display='none'; $('foco').classList.add('on'); $('fTit').textContent=c.tit; $('fLg').textContent=c.lg; - $('fPreco').textContent=c.preco; $('fSub').textContent=c.sub; $('zTit').textContent=c.zt; $('zSub').textContent=c.zs; + $('zManual').hidden=!ehFolha(m); + $('zOutra').textContent = ehFolha(m) ? 'Adicionar outra folha' : 'Adicionar mais artes'; + $('zona').classList.remove('compacta'); $('inp').multiple=c.multi; - $('inp').accept = ehFolha(m) ? '.png,.jpg,.jpeg,.pdf' + // The file decides the price: PNG, JPG and PDF are checked here, the others by hand. + $('inp').accept = ehFolha(m) ? '.png,.jpg,.jpeg,.pdf,.tif,.tiff,.psd,.psb,.ai,.cdr' : '.png,.jpg,.jpeg,.webp'; $('catFoco').className='cat '+(ehFolha(m)?'file':'av'); $('larguraFolhaPronta').textContent=String(c.larg).replace('.',','); @@ -46,8 +49,8 @@ function pintaTipoEnvio(){ if(el.hidden) return; const folha = ehFolha() ? modo : PAR[modo]; const avulsa = ehFolha() ? PAR[modo] : modo; - $('tipoFolhaPreco').textContent='a partir de '+rs(pisoEscada(folha)); - $('tipoAvulsaPreco').textContent='a partir de '+rs(pisoEscada(avulsa))+' · montagem inclusa'; + $('tipoFolhaPreco').textContent=rs(pisoEscada(folha))+' a '+rs(TABELA[folha]).slice(3)+' /m'; + $('tipoAvulsaPreco').textContent='+ '+rs(MONTAGEM[avulsa])+' /m'; $('larguraFolhaPronta').textContent=String(MODOS[folha].larg).replace('.',','); const atual = ehFolha() ? 'folha' : 'avulsa'; el.querySelectorAll('.cam').forEach(b=>{ @@ -89,8 +92,7 @@ function trocaTipo(destino){ modo=destino; history.replaceState(history.state,'',PAGINAS[modo]); document.title=tituloPagina(); $('lista').innerHTML=''; $('rA').style.display='none'; recusa([]); - caminho='auto'; avisoCam(''); - pintaModo(); pintaCaminhos(); limpaPaineis(); agendaAvaliacao(); previaAoVivo(); + pintaModo(); limpaPaineis(); agendaAvaliacao(); previaAoVivo(); } $('bVoltar').addEventListener('click',()=>{ itemAtual=null; modo=null; $('atual').style.display='none'; $('carrLin').innerHTML=''; pintaPedido(); diff --git a/web/site-packing.js b/web/site-packing.js index 05c6881..9edfdcf 100644 --- a/web/site-packing.js +++ b/web/site-packing.js @@ -286,6 +286,7 @@ function previaAoVivo(){ clearTimeout(tMont); montagemLayout=null; $('vArea').montagemVersao=($('vArea').montagemVersao||0)+1; + if(!ehFolha()) $('bAmpliar').hidden=true; if(ehFolha()){ $('vUso').innerHTML=''; const tot=folhaTotalM(); @@ -319,7 +320,9 @@ function previaAoVivo(){ figura.append(pilha,legenda); painel.append(figura); }); $('vArea').replaceChildren(painel); + $('bAmpliar').hidden=false; }else{ + $('bAmpliar').hidden=true; $('vArea').innerHTML = medidas.length ? '
'+(medidas.length>1 ? medidas.length+' folhas · '+fmtM(tot)+' m' diff --git a/web/site-pdf.js b/web/site-pdf.js index 929ad87..26a1b01 100644 --- a/web/site-pdf.js +++ b/web/site-pdf.js @@ -356,6 +356,15 @@ function textoProgresso(x){ if(x.med && x.med.grande) return 'gerando a prévia e conferindo a arte… '+x.pct+'%'; return x.pct<50?'lendo o arquivo…':x.pct<70?'medindo a folha…':'conferindo a arte…'; } +// The file card's thumbnail (52 x 96 px, drawn at twice that for sharp screens). +function miniatura(fonte){ + const w=fonte.naturalWidth||fonte.width, h=fonte.naturalHeight||fonte.height; + if(!(w>0 && h>0)) return null; + const s=Math.min(1,104/w,192/h), cv=document.createElement('canvas'); + cv.width=Math.max(1,Math.round(w*s)); cv.height=Math.max(1,Math.round(h*s)); + cv.getContext('2d').drawImage(fonte,0,0,cv.width,cv.height); + return cv.toDataURL('image/webp',0.8); +} // Moves one sheet's progress bar in place: repainting the whole list and the // preview on every step made "Sua folha" flicker while a large file was read. function pintaProgressoFolha(x){ @@ -364,66 +373,79 @@ function pintaProgressoFolha(x){ if(!barra){ pintaFolha(); return; } barra.style.width=x.pct+'%'; if(texto) texto.textContent=textoProgresso(x); } +// What the check found, as chips: ok (verde), av (atenção), er (resolva você), +// fix (arrumamos de graça), nt (a equipe confere). Details stay one click away. +function chipsDaFolha(a){ + const chip=(k,t)=>'
  • '+t+'
  • '; + const dpi = a.vetor ? chip('ok','Arte vetorial') + : chip(a.dpi>=DPI_AVISA?'ok':a.dpi>=DPI_RECUSA?'av':'er', a.dpi+' DPI'); + if(a.grande) return dpi+chip('nt','Peças, resíduos e fundo: a equipe confere'); + return dpi+ + (a.fundoChapado? chip('er','Fundo chapado') : chip('ok','Fundo transparente'))+ + (a.residuos? chip('er',a.residuos+' resíduo'+(a.residuos>1?'s':'')) : chip('ok','Sem resíduos'))+ + (a.encostadas? chip('fix',a.encostadas+' peças coladas · separamos grátis') : chip('ok','Peças separadas')); +} +function avisosDaFolha(a){ + if(a.grande) return ''; + return (a.fundoChapado? '

    O fundo não é transparente. '+ + 'Branco parecendo transparente sai branco no filme. Exporte com fundo transparente.

    ' : '')+ + (a.residuos? '

    '+a.residuos+' pontinho'+(a.residuos>1?'s soltos serão impressos':' solto será impresso')+ + '. A impressora imprime qualquer resíduo de recorte. Apague no arquivo e envie de novo.

    ' : ''); +} +function detalhesDaFolha(a,i,aberto){ + const linhas = a.grande + ? ['Resolução '+a.dpi+' DPI, lida do arquivo', + 'Arquivo grande: peças, resíduos e fundo são conferidos pela equipe'] + : [a.artes+' peça'+(a.artes===1?'':'s')+' · '+a.aproveitamento+'% da folha com arte', + 'Resolução '+a.dpi+' DPI · '+(a.fonteDpi==='imagens'? 'medida imagem por imagem dentro do PDF' + : a.fonteDpi==='vetor'? 'arte vetorial, sem imagem embutida' : 'lida do arquivo'), + 'Conferido numa grade de '+n1(a.grade)+' mm']; + return '
    '+ + 'Ver detalhes da conferência'+ + linhas.map(l=>''+l+'').join('')+'
    '; +} function pintaFolha(){ invalidaItemAtual(); const L=larguraFilme(); pintaTipoEnvio(); // trava o seletor enquanto houver folha + $('zona').classList.toggle('compacta', folhas.length>0); if(!folhas.length){ $('lista').innerHTML=''; agendaAvaliacao(); previaAoVivo(); return; } - $('lista').innerHTML = folhas.map((x,i)=>{ + const tot=folhaTotalM(); + $('lista').innerHTML = '

    Seus arquivos

    '+ + folhas.length+' folha'+(folhas.length>1?'s':'')+(tot>0? ' · '+fmtM(tot)+' m' : '')+'
    '+ + folhas.map((x,i)=>{ const lido=!!x.med, larga=lido && x.med.larg>L, suspeito=lido && x.med.foraDoPadrao; - const sub=(x.m||0)*(x.rep||1); - let medida=''; + const sub=(x.m||0)*(x.rep||1), a=lido && x.an; + let medida='', manual=''; if(lido){ - const a=x.an; - const conferido = a && a.grande - ? '
    Arquivo grande · '+a.dpi+' DPI'+ - 'nota pela resolução · peças, resíduos e fundo conferidos pela equipe
    ' - : a - ? '
    Conferido de verdade'+ - ''+a.artes+' peça'+(a.artes===1?'':'s')+' · '+a.aproveitamento+ - '% da folha virou arte · '+ - (a.residuos? a.residuos+' resíduo'+(a.residuos>1?'s':'') : 'sem resíduo')+' · '+ - (a.fundoChapado? 'fundo chapado' : 'fundo transparente')+''+ - 'resolução '+a.dpi+' DPI · '+ - (a.fonteDpi==='imagens'? 'medida imagem por imagem dentro do PDF' - : a.fonteDpi==='vetor'? 'arte vetorial, sem imagem embutida' - : 'lida do arquivo')+ - ' · grade de '+n1(a.grade)+' mm
    ' - : ''; - medida='
    '+ - ''+n1(x.med.larg)+' × '+n1(x.med.alt)+' cm'+ - ''+x.med.fonte+' · '+fmtM(x.m)+' m de folha'+ - conferido+ - (suspeito? 'Este PDF passa do tamanho que o formato comporta. '+ + medida='
    '+n1(x.med.larg)+' × '+n1(x.med.alt)+' cm'+ + ''+escapeHTML(extDe(x.f.name))+' · '+fmt(x.f.size)+'
    '+ + (a? '
      '+chipsDaFolha(a)+'
    '+avisosDaFolha(a)+detalhesDaFolha(a,i,x.detAberto) : '')+ + (suspeito? '

    Este PDF passa do tamanho que o formato comporta. '+ 'A especificação para em 508 cm e o seu tem '+n1(x.med.alt)+' cm. '+ 'Ele abre certo só em quem o gerou — aqui vai precisar de tratamento. '+ - 'Manda em PNG ou TIFF, ou divide em partes de até 5 m, que sai na hora.':'')+ - (larga? 'Esta folha não roda neste filme. Ela tem '+n1(x.med.larg)+ + 'Manda em PNG ou TIFF, ou divide em partes de até 5 m, que sai na hora.

    ':'')+ + (larga? '

    Esta folha não roda neste filme. Ela tem '+n1(x.med.larg)+ ' cm de largura e o filme aqui tem '+n1(L)+' cm. Não dá para reduzir: '+ 'encolher a folha encolheria cada arte junto.'+ (x.med.larg<=57.5 ? ' Ela cabe no DTF têxtil de 57 cm — troque de produto ali em cima.' - : ' Remonte a folha em '+n1(L)+' cm e suba de novo.')+'':'')+ - '

    '; + : ' Remonte a folha em '+n1(L)+' cm e suba de novo.')+'

    ':''); }else if(x.measurementError){ - medida='
    Este PDF não pode ser orçado'+ - escapeHTML(x.measurementError)+'
    '; + medida=''+escapeHTML(extDe(x.f.name))+' · '+fmt(x.f.size)+''+ + '

    Este PDF não pode ser orçado. '+escapeHTML(x.measurementError)+'

    '; }else{ const teto=TABELA[modo], piso=pisoEscada(); const dif=(x.m>0)? (teto-piso)*cobrar(x.m*(x.rep||1)) : 0; - medida='
    '+ - ''+escapeHTML(extDe(x.f.name))+' não abre no navegador'+ - 'Sem conseguir conferir o arquivo, não temos como dar nota — e sem nota '+ - 'o metro sai pela tabela, '+rs(teto)+'. Alguém vai abrir esse arquivo na mão '+ - 'antes de imprimir.'+ - '
    Exportando a mesma folha em PNG ou PDF, a conferência é '+ - 'automática e o metro pode cair até '+rs(piso)+''+ - (dif>0.5? ' — '+rs(dif)+' a menos só nesta folha' : '')+'.
    '+ - 'Informe o comprimento para seguir:'+ - ''+ - '
    '; + medida='Conferência manual · preço cheio'+ + '

    O navegador não abre '+escapeHTML(extDe(x.f.name))+', então alguém da equipe '+ + 'confere antes de imprimir e o metro sai pela tabela, '+rs(teto)+'. '+ + 'Exportando em PNG ou PDF, o metro pode cair até '+rs(piso)+''+ + (dif>0.5? ' — '+rs(dif)+' a menos só nesta folha' : '')+'.

    '; + manual='
    '+ + 'm
    '; } const barra = x.pct!=null ? '
    '+ @@ -433,36 +455,41 @@ function pintaFolha(){ '. Seguimos com o preço de tabela — se quiser a nota e o desconto, exporte a mesma '+ 'folha em PNG, que a conferência é bem mais leve.
    ' : ''; - return '
    '+ - (folhas.length>1? (i+1)+'. ':'')+escapeHTML(x.f.name)+''+ - ''+fmt(x.f.size)+''+ - '
    '+ - barra+medida+ - (x.m>0 ? - '
    '+ - '
    '+ - '
    '+ - '
    '+fmtM(sub)+' m'+ - (x.rep>1? ' · '+x.rep+' × '+fmtM(x.m)+' m':'')+'
    '+ - '
    ' : '')+ + // A small thumbnail made once: the list is rebuilt on every change, and the + // full preview of a file up to 150 MB would be re-parsed each time. + const mini = x.miniSrc + ? '' + : ''+escapeHTML(extDe(x.f.name))+''; + const copias = x.m>0 || manual ? + '
    '+manual+ + (x.m>0 ? + '
    '+ + ''+ + ''+ + '
    '+ + '
    '+(x.rep>1? x.rep+' × '+fmtM(x.m)+' m = ' : '')+''+fmtM(sub)+' m
    ' : '')+ + '
    ' : ''; + return '
    '+ + '
    '+mini+'
    '+ + '
    '+(folhas.length>1? (i+1)+'. ':'')+escapeHTML(x.f.name)+''+ + '
    '+ + (lido || x.measurementError ? '' : ''+escapeHTML(extDe(x.f.name))+' · '+fmt(x.f.size)+'')+ + barra+medida+ + '
    '+copias+ '
    '; }).join(''); - // total do pedido, quando há mais de uma folha - const tot=folhaTotalM(), partes=Math.ceil(tot/20); - if(folhas.length>1 && tot>0){ - $('lista').innerHTML += '
    '+ - ''+folhas.length+' folhas neste pedido'+ - ''+fmtM(tot)+' m no total'+ - (partes>1? 'vai em '+partes+' partes de até 20 m':'')+'
    '; - }else if(partes>1 && tot>0){ - $('lista').innerHTML += '
    folha longa'+ - ''+fmtM(tot)+' mvai em '+partes+' partes de até 20 m
    '; - } - $('lista').querySelectorAll('[data-rmf]').forEach(b=>b.addEventListener('click',()=>{ folhas.splice(+b.dataset.rmf,1); pintaFolha(); })); + $('lista').querySelectorAll('[data-det]').forEach(d=>d.addEventListener('toggle',()=>{ + folhas[+d.dataset.det].detAberto=d.open; + })); + $('lista').querySelectorAll('[data-passo]').forEach(b=>b.addEventListener('click',()=>{ + const el=$('repf'+b.dataset.i); + el.value=Math.max(1,Math.min(200,(+el.value||1)+(+b.dataset.passo))); + el.dispatchEvent(new Event('change')); + })); $('lista').querySelectorAll('[data-repf]').forEach(el=>el.addEventListener('change',e=>{ folhas[+el.dataset.repf].rep=Math.max(1,Math.min(200,+e.target.value||1)); pintaFolha(); })); @@ -501,6 +528,7 @@ function pintaProgressoArte(a){ } function pintaArtes(){ invalidaItemAtual(); + $('zona').classList.toggle('compacta', artes.length>0); $('lista').innerHTML=artes.map((a,i)=>{ let barra='', dica='', calc='informe a largura para ver a qualidade'; if(a.lendo!=null){ diff --git a/web/site-upload.js b/web/site-upload.js index ec52099..77fea3b 100644 --- a/web/site-upload.js +++ b/web/site-upload.js @@ -48,21 +48,6 @@ function sel(fs){ } if(!fs.length) return; if(ehFolha()){ - const auto=fs.filter(f=>AUTO.test(f.name)).length; - const manual=fs.length-auto; - if(caminho==='auto' && manual){ - caminho='tabela'; - avisoCam('Trocamos o caminho para você. Você marcou conferência automática, '+ - 'mas '+(manual>1? manual+' arquivos vieram':'o arquivo veio')+' em formato que não '+ - 'abrimos. O metro vai pela tabela, '+rs(TABELA[modo])+'.'); - pintaCaminhos(); - }else if(caminho==='tabela' && auto){ - caminho='auto'; - avisoCam('Boa notícia. Você marcou o caminho sem conferência, mas '+ - (auto>1? 'os arquivos vieram':'o arquivo veio')+' em formato que a gente confere. '+ - 'Vamos avaliar e o metro pode cair até '+rs(pisoEscada())+'.'); - pintaCaminhos(); - } const novas=fs.map(f=>({f, med:null, rep:1, m:0, semAnalise:null})); folhas=folhas.concat(novas); // soma, não substitui pintaFolha(); @@ -87,7 +72,7 @@ function sel(fs){ if(pct-mostrado>=1){ mostrado=pct; x.pct=pct; pintaProgressoFolha(x); } }).then(cv=>{ if(cv && folhas.includes(x)){ - x.previewSrc=cv.toDataURL('image/webp',0.85); + x.previewSrc=cv.toDataURL('image/webp',0.85); x.miniSrc=miniatura(cv); try{ const an=analisarFolha(cv, md.larg); x.an={...an, dpi:md.dpiFolha, fonteDpi:'arquivo', grande:false}; @@ -96,7 +81,7 @@ function sel(fs){ }).catch(()=>{}).finally(()=>{ x.pct=null; pintaFolha(); }); }else if(md && RENDERIZA.test(x.f.name)){ carregarImagem(x.f).then(img=>{ - if(img){ x.previewSrc=img.src; try{ x.an=analisarFolha(img, md.larg); if(x.an) x.an.fonteDpi='arquivo'; } + if(img){ x.previewSrc=img.src; x.miniSrc=miniatura(img); try{ x.an=analisarFolha(img, md.larg); if(x.an) x.an.fonteDpi='arquivo'; } catch(e){} } x.pct=null; pintaFolha(); }); @@ -112,6 +97,7 @@ function sel(fs){ : ''); } if(r && r.tela){ + x.miniSrc=miniatura(r.tela); try{ x.an=analisarFolha(r.tela, md.larg); // vetor puro não tem resolução · nota máxima, e está certo diff --git a/web/site-v2.css b/web/site-v2.css index c685c4c..a3ac1c8 100644 --- a/web/site-v2.css +++ b/web/site-v2.css @@ -104,35 +104,48 @@ section+section{border-top:0} .voltar:hover{color:var(--laranja-escuro)} .focoGrid{grid-template-columns:minmax(0,1fr);gap:20px} .cat,.cat.file{border:0;background:transparent;box-shadow:none;overflow:visible} -.cabfoco,.cat.file .cabfoco{padding:0 0 20px!important;background:transparent;border:0;display:grid; - grid-template-columns:minmax(0,1fr) auto;grid-template-areas:"t e" "s e" "p e";column-gap:24px;align-items:end} -.cabfoco>div:first-child{grid-area:t;display:flex;flex-direction:column-reverse;gap:4px} -.cabfoco .lg{font-size:12px;color:#707070;letter-spacing:.05em} -.cabfoco h3{font-size:32px;font-weight:800;letter-spacing:-.02em;line-height:1.1} -.cabfoco p{grid-area:s;margin-top:6px;font-size:15px;color:var(--texto2)} -.cabfoco .pr2{grid-area:p;margin-top:4px;font-size:14px;font-weight:600;color:var(--fraco);white-space:normal} -.tipoEnvio{grid-area:e;margin:0} -.tipoEnvio:not([hidden]){display:inline-flex;gap:4px;padding:4px;border-radius:10px;background:#EFEFEF} -.tipoEnvio .cam,.tipoEnvio .cam.on{border:0;box-shadow:none;background:transparent;padding:0 14px;min-height:40px;border-radius:8px;align-items:center} -.tipoEnvio .cam.on{background:#fff;box-shadow:0 1px 2px rgba(3,6,11,.14)} -.tipoEnvio .cam .mk2,.tipoEnvio .cam span,.tipoEnvio .cam em{display:none} -.tipoEnvio .cam b{margin:0;font-size:13.5px;font-weight:600;white-space:nowrap} -.tipoEnvio .cam.on b{font-weight:800} +.cabfoco,.cat.file .cabfoco{padding:0 0 24px!important;background:transparent;border:0;display:flex;flex-direction:column;gap:20px} +.cabfoco>div:first-child{display:flex;flex-direction:column-reverse;gap:4px} +.cabfoco .lg{font-size:12.5px;font-weight:800;color:var(--laranja-escuro);letter-spacing:.06em;text-transform:uppercase} +.cabfoco h3{font-size:36px;font-weight:800;letter-spacing:-.02em;line-height:1.1} +.tipoEnvio{margin:0} +.tipoEnvio:not([hidden]){display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;max-width:calc(100% - 452px)} +.tipoEnvio .cam,.tipoEnvio .cam.on{padding:14px 16px;min-height:0;border-radius:12px;border:1px solid var(--linha);background:#F9F9F9;box-shadow:none;align-items:flex-start} +.tipoEnvio .cam.on{padding:13px 15px;border:2px solid var(--preto);background:#fff} +.tipoEnvio .cam .mk2{display:none} +.tipoEnvio .cam div{display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:12px;row-gap:4px;align-items:baseline} +.tipoEnvio .cam b{margin:0;font-size:15px;font-weight:700;color:var(--texto2)} +.tipoEnvio .cam.on b{color:var(--preto);font-weight:800} +.tipoEnvio .cam em{margin:0;font-size:13px;font-weight:500;color:var(--fraco);white-space:nowrap} +.tipoEnvio .cam.on em{font-weight:600;color:var(--preto)} +.tipoEnvio .cam div>span{grid-column:1/-1;font-size:13px;color:var(--fraco);line-height:1.4} +.tipoEnvio .cam.on div>span{color:var(--texto2)} .tipoEnvio .cam:disabled{cursor:default} -.tipoEnvio .cam:disabled:not(.on){opacity:.5} +.tipoEnvio .cam:disabled:not(.on){opacity:.55} +@media(max-width:1100px){.tipoEnvio:not([hidden]){max-width:none}} .cat .in{padding:0!important} .foco2{grid-template-columns:minmax(0,1fr) 420px;gap:32px} .fila{display:flex;flex-direction:column;gap:12px} .fila>*{margin:0} .cam{border-radius:var(--raio2)} .cam.on{border-color:var(--laranja);background:var(--aviso-fundo)} -#larguraFolhaPronta{display:inline} +#larguraFolhaPronta{display:inline;font-size:inherit;color:inherit} .zona{display:grid;grid-template-columns:44px minmax(0,1fr);column-gap:16px;row-gap:2px;align-items:center;text-align:left;padding:16px 20px;margin:0;border:2px dashed #F2B25A;background:var(--aviso-fundo);border-radius:var(--raio)} .zona .ico{grid-row:1/4;display:flex;align-items:center;justify-content:center;width:44px;height:44px;line-height:1;margin:0;border-radius:10px;background:var(--laranja);color:var(--preto);font-size:20px;box-shadow:none} .zona b{font-size:15px;margin:0} .zona span{max-width:none;margin:0;font-size:13px;color:var(--fraco)} .zona .bt{display:none} .zona:hover,.zona.sobre{border-color:var(--laranja2);box-shadow:none} +.zona .zManual{grid-column:1/-1;margin-top:12px;padding-top:12px;border-top:1px solid var(--aviso-linha);color:var(--texto2);line-height:1.5} +.zona .zManual[hidden]{display:none} +.zona .zManual b{display:inline;font-size:13px} +.zona .zOutra{display:none} +.zona.compacta{display:flex;justify-content:center;align-items:center;min-height:56px;padding:0 20px;border:1.5px dashed #D0D0D0;background:#fff;cursor:pointer} +.zona.compacta>*{display:none} +.zona.compacta .zOutra{display:inline;font-size:14px;color:var(--fraco)} +.zona.compacta .zOutra b{display:inline;font-size:14px;font-weight:600;color:var(--preto)} +.zona.compacta .zOutra b::before{content:"+";margin-right:8px;font-weight:700} +.zona.compacta:hover,.zona.compacta.sobre{border-color:var(--laranja2)} #lista{display:flex;flex-direction:column;gap:10px} #lista:empty{display:none} .art{margin:0;padding:14px 16px;border-radius:12px;background:#fff;border:1px solid var(--linha)} @@ -141,14 +154,69 @@ section+section{border-top:0} .art label{font-size:12px} .art input{height:42px;font-size:15px;font-weight:600;border-radius:8px} .art .cps{grid-template-columns:repeat(2,minmax(0,160px))} -.rep{margin:0;padding:14px 16px;border-radius:12px;background:#fff;border:1px solid var(--linha)} +.listaCab{display:flex;justify-content:space-between;align-items:baseline;gap:12px} +.listaCab h4{margin:0;font-size:18px;font-weight:700} +.listaCab span{font-size:13px;color:var(--fraco)} +.rep{margin:0;padding:20px;border-radius:14px;background:#fff;border:1px solid var(--linha);display:flex;flex-direction:column;gap:16px} +.repTopo{display:flex;gap:16px;align-items:flex-start} +.miniF{flex:none;width:52px;height:96px;border-radius:6px;border:1px solid #D6D6D6;background:#F4F4F2;display:flex;align-items:center;justify-content:center;overflow:hidden} +.miniF img{width:100%;height:100%;object-fit:contain;display:block} +.miniF span{font-size:11px;font-weight:800;color:var(--texto2)} +.repInfo{flex:1;min-width:0;display:flex;flex-direction:column;gap:6px} +.rep .l1{margin:0} +.rep .l1 b{font-size:14px;font-weight:600;color:var(--preto)} +.rep .l1 button{width:32px;height:32px;margin:-6px -6px -6px 0;border-radius:8px;font-size:18px} +.rep .l1 button:hover{background:#F1F1F1;color:var(--preto)} +.repMed{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap} +.repMed b{font-family:"Inter",sans-serif;font-size:22px;font-weight:700;letter-spacing:-.01em} +.repMed span,.repPeso{font-size:13px;color:var(--fraco)} +.chips{list-style:none;margin:4px 0 0;padding:0;display:flex;flex-wrap:wrap;gap:8px} +.chip{display:inline-flex;align-items:center;gap:6px;padding:5px 10px;border-radius:999px;font-size:13px;font-weight:600;line-height:1.2} +.chip::before{font-weight:800} +.chip.ok{background:var(--verde-fundo);color:var(--verde)}.chip.ok::before{content:"✓"} +.chip.av{background:#FFF1DB;color:#8A4B00}.chip.av::before{content:"!"} +.chip.er{background:#FDE8E6;color:#B3261E}.chip.er::before{content:"×"} +.chip.fix{background:#E8F0FB;color:#1F4E8C}.chip.fix::before{content:"✓"} +.chip.nt{background:#F1F1F1;color:var(--texto2)} +.chipSo{align-self:flex-start;padding:5px 10px;border-radius:999px;background:#F1F1F1;color:var(--texto2);font-size:13px;font-weight:600} +.avisoF{margin:4px 0 0;padding:10px 12px;border-radius:10px;background:#FDE8E6;font-size:13px;line-height:1.5;color:var(--preto)} +.avisoF b{color:#B3261E} +.repTxt{margin:2px 0 0;font-size:13.5px;line-height:1.5;color:var(--texto2)} +.repTxt b{color:var(--preto)} +.confDet{font-size:13px} +.confDet summary{display:inline;cursor:pointer;list-style:none;color:var(--laranja-escuro);font-weight:500} +.confDet summary::-webkit-details-marker{display:none} +.confDet summary:hover{text-decoration:underline} +.confDet[open] summary{display:inline-block;margin-bottom:6px} +.confDet span{display:block;color:var(--texto2);line-height:1.6} +.rep .cps{display:flex;align-items:center;gap:16px 24px;flex-wrap:wrap;margin:0;padding-top:16px;border-top:1px solid #EFEFEF} +.rep .campo{display:flex;align-items:center;gap:12px} +.rep .campo label{margin:0;font-size:14px;font-weight:600;color:var(--preto)} +.passo{display:inline-flex;border:1px solid #D6D6D6;border-radius:10px;overflow:hidden} +.passo button{width:44px;height:44px;border:0;background:#F9F9F9;font-size:18px;color:var(--preto);cursor:pointer} +.passo button:hover{background:#EFEFEF} +.rep .passo input{width:56px;height:44px;padding:0;border:0;border-radius:0;text-align:center;font-size:16px;font-weight:700;-moz-appearance:textfield;appearance:textfield} +.passo input::-webkit-inner-spin-button,.passo input::-webkit-outer-spin-button{-webkit-appearance:none;margin:0} +.rep .un{display:inline-flex;align-items:center;gap:6px;height:44px;padding:0 12px;border:1px solid #D6D6D6;border-radius:10px} +.rep .un input{width:64px;padding:0;border:0;font-size:16px;font-weight:700;text-align:right} +.rep .un i{font-style:normal;font-size:14px;color:var(--fraco)} +.rep .conta{margin-left:auto;font-size:14px;color:var(--texto2)} +.rep .conta b{font-family:"Inter",sans-serif;font-size:16px;color:var(--preto)} .calc{font-size:13px;margin-top:8px} .dica{display:flex;align-items:center;gap:12px;margin-top:10px;padding:10px 12px;border:0;border-radius:8px;background:var(--verde-fundo);font-size:13px;color:#14532D} .dica.av{background:var(--aviso-fundo);color:#5A3A00} .dica button{display:inline-flex;width:auto;margin:0 0 0 auto;flex:none;height:34px;align-items:center;padding:0 12px;border-radius:7px;border:1px solid var(--verde);background:#fff;color:var(--verde);box-shadow:none;font-size:13px} .dica button:hover{background:var(--verde);color:#fff;box-shadow:none} -.req{position:static;padding:16px 20px 6px;border-radius:12px;box-shadow:none} -.reqcab{font-size:15px;margin-bottom:6px} +.req{position:static;padding:8px 0 0;border:0;border-radius:0;background:none;box-shadow:none;display:flex;flex-wrap:wrap;align-items:baseline;gap:8px 20px} +.reqcab{margin:0;font-size:13px;font-weight:400;color:var(--fraco)} +.req details,.req details:first-of-type{border:0} +.req summary{display:inline;padding:0;font-size:13px;font-weight:500;color:var(--laranja-escuro)} +.req summary::before{display:none} +.req summary:hover{text-decoration:underline} +.req details[open]{order:1;flex-basis:100%;padding:14px 16px 4px;border-radius:12px;background:var(--cinza)} +.req details[open] summary{display:block;margin-bottom:6px;font-size:14px;font-weight:700;color:var(--preto);text-decoration:none} +.req li{font-size:13px} +.req .obs2{font-size:12px} /* The buy box */ .mont{position:sticky;top:var(--topo-passos,128px);padding:20px;border-radius:16px;background:#fff;box-shadow:none;display:flex;flex-direction:column;gap:12px} @@ -160,12 +228,36 @@ section+section{border-top:0} .compra .aoVivo.pronto{display:none} #compraVals{display:flex;flex-direction:column;gap:10px;font-size:15px} #compraVals[hidden]{display:none} -.cNota{display:flex;align-items:center;gap:12px} -.cNota span,.cLin>span:first-child{color:var(--texto2)} -.cNota>i{flex:1;height:6px;border-radius:999px;background:#EFEFEF;overflow:hidden} -.cNota>i i{display:block;height:100%;border-radius:999px;background:#C9CCD1} -.cNota>i i.ok{background:var(--verde)}.cNota>i i.av{background:var(--laranja)}.cNota>i i.er{background:var(--vermelho)} -.cNota b{font-family:"Inter",sans-serif;font-weight:800} +.cat.file .zoomB{display:none} +.ampliar{margin-left:auto;height:32px;padding:0 12px;border-radius:8px;border:1px solid #D6D6D6;background:#fff;font-size:12.5px;font-weight:600;color:var(--preto);cursor:pointer} +.ampliar:hover{border-color:var(--preto)} +.ampliar[hidden]{display:none} +.cat.file #vArea{max-height:340px} +.cEscada{display:flex;flex-direction:column;gap:8px;margin-bottom:4px} +.cEscada>span{font-size:13px;font-weight:600} +.cEscada ol{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:4px} +.cEscada li{padding:8px 2px;border-radius:8px;background:#F4F4F2;border:1.5px solid transparent;display:flex;flex-direction:column;align-items:center;gap:2px} +.cEscada li span{font-size:11px;color:var(--fraco);white-space:nowrap} +.cEscada li b{font-size:13px;font-weight:500;color:var(--texto2)} +.cEscada li.on{background:var(--verde-fundo);border-color:var(--verde)} +.cEscada li.on span,.cEscada li.on b{font-weight:700;color:var(--verde)} +.cEscada li.on:last-child{background:#F1F1F1;border-color:var(--preto)} +.cEscada li.on:last-child span,.cEscada li.on:last-child b{color:var(--preto)} +.cLin>span:first-child{color:var(--texto2)} +.cLin small{font-size:12px;color:var(--fraco)} +.cEco{margin:-6px 0 0;text-align:right;font-size:13px;font-weight:600;color:var(--verde)} +.cEco:empty{display:none} +#cPartes{display:block} +.ampliaDlg{width:min(960px,calc(100vw - 32px));max-height:calc(100vh - 48px);padding:0;border:0;border-radius:16px;box-shadow:0 20px 60px rgba(3,6,11,.3)} +.ampliaDlg::backdrop{background:rgba(3,6,11,.55)} +.ampliaCab{position:sticky;top:0;z-index:1;display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--linha);background:#fff} +.ampliaCab b{font-size:16px;font-weight:800} +.ampliaCab button{width:40px;height:40px;border:0;border-radius:8px;background:#F1F1F1;font-size:20px;cursor:pointer} +#ampliaArea .folhaPrevias{display:grid;gap:16px;padding:16px;background:#F8F9FA} +#ampliaArea .folhaPrevia{margin:0;background:#fff;border:1px solid var(--linha);border-radius:8px;overflow:hidden} +#ampliaArea .folhaPilha{display:flex;flex-direction:column;align-items:center;gap:4px} +#ampliaArea .folhaPilha img{display:block;width:auto;max-width:100%;height:auto;max-height:calc(100vh - 180px)!important} +#ampliaArea figcaption{padding:8px 12px;font-size:13px;color:var(--texto2);border-top:1px solid var(--linha)} .cLin{display:flex;align-items:baseline;gap:8px} .cLin>span:last-child,.cLin>b{margin-left:auto;display:flex;gap:8px;align-items:baseline} .cLin s{font-size:13px;color:#707070} @@ -184,8 +276,14 @@ section+section{border-top:0} .cPe{margin:0;font-size:13px;color:var(--fraco);text-align:center} @media(max-width:1100px){.foco2{grid-template-columns:1fr}.mont{position:static}} @media(max-width:620px){.montcab b{font-size:15px} - .cabfoco,.cat.file .cabfoco{grid-template-columns:1fr;grid-template-areas:"t" "s" "p" "e"} - .tipoEnvio:not([hidden]){display:grid;grid-template-columns:1fr 1fr;margin-top:14px}} + .cabfoco h3{font-size:28px} + .tipoEnvio .cam div{grid-template-columns:1fr} + .tipoEnvio .cam div>span{display:none} + .rep{padding:16px} + .repTopo{gap:12px} + .miniF{width:40px;height:80px} + .repMed b{font-size:20px} + .rep .conta{margin-left:0}} /* The quality, preview, cart and checkout panels sit directly in #envio, outside .w; they share the page column so nothing runs edge to edge. */ @@ -231,6 +329,8 @@ html:is([data-rota="pagamento"],[data-rota="pix"]) .checkout{max-width:1040px;ma html:is([data-rota="pagamento"],[data-rota="pix"]) .pagGrid{display:grid;grid-template-columns:minmax(0,1fr) 340px;gap:32px;align-items:start} .envioArq{font-size:13px;color:var(--texto2);margin-top:14px;line-height:1.5} .envioArq.ok{color:var(--verde)} +.envioArq.erro{color:#B42318} +.envioDeNovo{margin-left:4px;padding:0;border:0;background:none;color:inherit;font:inherit;font-weight:700;text-decoration:underline;cursor:pointer} .envioBarra{height:6px;border-radius:999px;background:#EDEDED;overflow:hidden;margin-bottom:6px} .envioBarra i{display:block;height:100%;background:var(--laranja);border-radius:999px;transition:width .4s} .cartEnvio{font-size:13px;font-weight:700;color:var(--laranja-escuro);margin-left:6px}