←
R$
Carregando…
↗ Ver site
`; } async function nxGetSite(api,id){ try{const r=await fetch(api+'/Site/'+encodeURIComponent(id));if(r.ok){const j=await r.json();const x=j.record||j;if(x&&String(x.id)===String(id))return x}}catch(e){} try{const r=await fetch(api+'/Site?id='+encodeURIComponent(id)+'&limit=5');if(r.ok){const j=await r.json();const x=(j.records||[]).find(z=>String(z.id)===String(id));if(x)return x}}catch(e){} let off=0;for(let k=0;k<20;k++){const r=await fetch(api+'/Site?limit=200&offset='+off);if(!r.ok)break;const j=await r.json();const L=j.records||[];const x=L.find(z=>String(z.id)===String(id));if(x)return x;if(L.length<200)break;off+=200} return null; } /* ==== /NX-RENDER ==== */ const P='https://wish4.com/api/projects/1793',API=P+'/data'; const $=s=>document.querySelector(s),esc=nxE; const ID=new URLSearchParams(location.search).get('id'); let rec=null,D=null,open=new Set([0]),tab='secs',saveT=null,renT=null,dirty=false,libPath=null; function toast(m,err){const t=$('#toast');t.textContent=m;t.className='toast show'+(err?' err':'');clearTimeout(t._t);t._t=setTimeout(()=>t.className='toast',3500)} function setSt(m,c){const s=$('#st');s.textContent=m;s.className='st '+(c||'')} const UIMG=id=>'https://images.unsplash.com/photo-'+id+'?w=1400&q=80&auto=format&fit=crop'; const LIB=['1503951914875-452162b0f3f1','1585747860715-2ba37e788b70','1560066984-138dadb4c035','1522337360788-8b13dee7a37e','1517248135467-4c7edcad34c4','1414235077428-338989a2e8c0','1555396273-367ea4eb4db5','1568901346375-23c9450c58cd','1534438327276-14e5300c3a48','1571019613454-1cb2f99b2d8b','1606811971618-4486d14f3f99','1519494026892-80bbd2d6fd0d','1576091160550-2173dba999ef','1589829545856-d10d557cf95f','1450101499163-c8848c66ca85','1600585154340-be6161a56a0c','1512917774080-9991f1c4c750','1554118811-1e0d58224f24','1495474472287-4d71bcdd2085','1587300003388-59208cc962cb','1450778869180-41d0601e046e','1570172619644-dfd03ed5d881','1544161515-4ab6ce6db874','1486262715619-67b85e0b08d3','1504307651254-35680f356dfd','1519741497674-611481863552','1460925895917-afdab827c52f','1542744173-8e7e53415bb0','1497366216548-37526070297c','1600880292203-757bb62b4baf','1556761175-5973dc0f32e7','1521791055366-0d553872125f'].map(UIMG); const SW=['#00ff84','#d4a24c','#c9a45c','#e8a5b8','#ff7a1a','#e63b2e','#ff4d2e','#c6ff00','#1fb6d5','#16a394','#2f6bff','#8b5cf6','#ff4d8d','#e9e4da']; const SC={ hero:{l:'Capa principal',ic:'🏁',f:[['tag','Etiqueta'],['title','Título principal','a'],['subtitle','Subtítulo','a'],['cta','Botão principal (abre o WhatsApp)'],['cta2','Botão secundário'],['image','Imagem de fundo','img']]}, about:{l:'Sobre',ic:'📖',f:[['kicker','Chamada pequena'],['title','Título'],['text','Texto','a'],['image','Imagem','img']],li:{k:'stats',l:'Números em destaque',f:[['n','Número'],['l','Legenda']],nw:{n:'100+',l:'novo destaque'}}}, services:{l:'Serviços',ic:'🧩',f:[['title','Título'],['subtitle','Subtítulo','a']],li:{k:'items',l:'Serviços',f:[['icon','Ícone (emoji)'],['title','Nome'],['text','Descrição','a'],['price','Preço (opcional)']],nw:{icon:'⭐',title:'Novo serviço',text:'Descreva este serviço.'}}}, gallery:{l:'Galeria',ic:'🖼️',f:[['title','Título'],['subtitle','Subtítulo','a']],li:{k:'images',l:'Imagens',f:[['src','Imagem','img']],nw:{src:''}}}, testimonials:{l:'Depoimentos',ic:'💬',f:[['title','Título'],['subtitle','Subtítulo','a']],li:{k:'items',l:'Depoimentos',f:[['name','Nome'],['role','Descrição (ex.: Cliente)'],['text','Depoimento','a']],nw:{name:'Novo cliente',role:'Cliente',text:'Experiência incrível!'}}}, pricing:{l:'Planos e preços',ic:'💎',f:[['title','Título'],['subtitle','Subtítulo','a']],li:{k:'items',l:'Planos',f:[['name','Nome do plano'],['price','Preço'],['features','Itens incluídos (um por linha)','a'],['featured','Destacar como "Mais escolhido"','chk']],nw:{name:'Novo plano',price:'R$ 99',features:'Item 1\nItem 2\nItem 3'}}}, faq:{l:'Perguntas frequentes',ic:'❓',f:[['title','Título']],li:{k:'items',l:'Perguntas',f:[['q','Pergunta'],['a','Resposta','a']],nw:{q:'Nova pergunta?',a:'Resposta aqui.'}}}, cta:{l:'Chamada para ação',ic:'📣',f:[['title','Título','a'],['text','Texto','a'],['cta','Texto do botão']]}, text:{l:'Texto livre',ic:'📝',f:[['kicker','Chamada pequena'],['title','Título'],['text','Texto','a'],['image','Imagem (opcional)','img']]}, contact:{l:'Contato',ic:'📍',f:[['title','Título'],['text','Texto','a'],['map','Mostrar mapa do endereço','chk']]} }; const NEW={hero:{type:'hero',tag:'',title:'Novo título impactante',subtitle:'Escreva aqui uma frase que convença o visitante.',cta:'Fale conosco',cta2:'Saiba mais',image:LIB[28]},about:{type:'about',kicker:'Nossa história',title:'Sobre nós',text:'Conte a história do negócio.',image:LIB[29],stats:[]},services:{type:'services',title:'Serviços',subtitle:'',items:[{icon:'⭐',title:'Serviço',text:'Descrição do serviço.'}]},gallery:{type:'gallery',title:'Galeria',subtitle:'',images:[{src:LIB[30]},{src:LIB[31]},{src:LIB[28]}]},testimonials:{type:'testimonials',title:'Depoimentos',items:[{name:'Cliente',role:'Cliente',text:'Experiência incrível!'}]},pricing:{type:'pricing',title:'Planos',items:[{name:'Plano',price:'R$ 99',features:'Item 1\nItem 2',featured:true}]},faq:{type:'faq',title:'Perguntas frequentes',items:[{q:'Pergunta?',a:'Resposta.'}]},cta:{type:'cta',title:'Vamos conversar?',text:'Fale com a gente agora.',cta:'Chamar no WhatsApp'},text:{type:'text',kicker:'',title:'Novo bloco de texto',text:'Escreva aqui o conteúdo.',image:''},contact:{type:'contact',title:'Contato',text:'Estamos prontos para te atender.',map:true}}; const INFO=[['name','Nome do negócio'],['niche','Nicho / segmento'],['whatsapp','WhatsApp (com DDD) — botões e ícone flutuante'],['email','E-mail'],['address','Endereço completo (aparece no mapa)'],['instagram','Instagram (sem @)'],['hours','Horário de funcionamento'],['navCta','Texto do botão do menu'],['logo','Logo (opcional — substitui o nome no topo)','img'],['seo','Descrição do site (Google e rodapé)','a']]; const getP=(o,p)=>p.split('.').reduce((a,k)=>a==null?a:a[k],o); function setP(o,p,v){const ks=p.split('.');let a=o;for(let i=0;iJSON.parse(JSON.stringify(o)); function fld(path,label,type,val){ const id='f_'+path.replace(/\W/g,'_'); if(type==='chk')return ``; if(type==='img')return `
`; if(type==='a')return `
`; return `
`; } function listEd(s,i,li){const arr=s[li.k]||[];return `
${arr.map((it,j)=>`
#${j+1}
${li.f.map(f=>fld(`sections.${i}.${li.k}.${j}.${f[0]}`,f[1],f[2],it[f[0]])).join('')}
`).join('')}
`} function secCard(s,i){const c=SC[s.type]||{l:s.type,ic:'▪',f:[]},op=open.has(i),n=D.sections.length; return `
${c.ic}
${c.l}${s.hidden?' · oculta':''}${esc(s.title||'')}
${op?`
${c.f.map(f=>fld(`sections.${i}.${f[0]}`,f[1],f[2],s[f[0]])).join('')}${c.li?listEd(s,i,c.li):''}
`:''}
`} function renderSide(){ const el=$('#side'); if(tab==='secs'){el.innerHTML=`
💡 Clique em qualquer parte da prévia para editar aquela seção. Use ↑ ↓ para reordenar, 👁 para ocultar.
`+D.sections.map(secCard).join('')+`
`} else if(tab==='info'){el.innerHTML=`
Dados do negócio usados no topo, botões de WhatsApp, contato, mapa e rodapé.
`+INFO.map(f=>fld(f[0],f[1],f[2],D[f[0]])).join('')} else{const t=D.theme;el.innerHTML=`
${SW.map(c=>``).join('')}
${[['dark','🌑 Escuro'],['light','☀️ Claro']].map(o=>``).join('')}
${Object.keys(NXF).map(k=>``).join('')}
${[['reto','▢ Retos'],['suave','▢ Suaves'],['redondo','◯ Redondos']].map(o=>``).join('')}
`} } function preview(){const f=$('#pv');let y=0;try{y=f.contentWindow.scrollY||0}catch(e){}f.onload=()=>{try{f.contentWindow.scrollTo(0,y)}catch(e){}};f.srcdoc=nxRender(D,true)} function changed(re=true){dirty=true;setSt('● Não salvo');if(re){clearTimeout(renT);renT=setTimeout(preview,280)}clearTimeout(saveT);saveT=setTimeout(save,1600)} function rs(){renderSide();changed()} async function save(){ clearTimeout(saveT);if(!rec)return; const data=JSON.stringify(D),size=new Blob([data]).size; if(size>7600){setSt('⚠ Conteúdo grande demais ('+(size/1024).toFixed(1)+' KB de 7,4). Encurte textos ou remova itens.','err');return} setSt('Salvando…'); try{const r=await fetch(API+'/Site/'+rec.id,{method:'PATCH',headers:{'Content-Type':'application/json'},body:JSON.stringify({name:rec.name||D.name||'Sem nome',client:rec.client||'',niche:D.niche||'',status:rec.status||'Rascunho',price:Number(rec.price)||0,data})}); const j=await r.json().catch(()=>({}));if(!r.ok)throw new Error(r.status===401||r.status===403?'apenas o administrador pode salvar (abra pelo editor do wish4)':(j.error||'erro '+r.status)); dirty=false;setSt('✓ Salvo','ok')}catch(e){setSt('Erro ao salvar: '+e.message,'err')} } function focusPrev(i){try{const el=$('#pv').contentDocument.querySelector('[data-i="'+i+'"]');el&&el.scrollIntoView({behavior:'smooth',block:'start'})}catch(e){}} $('#side').addEventListener('click',e=>{ const b=e.target.closest('[data-mv],[data-hd],[data-dp],[data-rm],[data-imv],[data-irm],[data-iadd],[data-up],[data-lib],[data-sw],[data-set],[data-add],[data-tg]');if(!b)return;const ds=b.dataset; if(ds.mv){const[i,dir]=ds.mv.split(',').map(Number),j=i+dir;if(j<0||j>=D.sections.length)return;[D.sections[i],D.sections[j]]=[D.sections[j],D.sections[i]];open=new Set([j]);rs();setTimeout(()=>focusPrev(j),400);return} if(ds.hd){const s=D.sections[+ds.hd];s.hidden=!s.hidden;rs();return} if(ds.dp){const i=+ds.dp;D.sections.splice(i+1,0,clone(D.sections[i]));open=new Set([i+1]);rs();return} if(ds.rm){const i=+ds.rm;if(!confirm('Excluir a seção "'+((SC[D.sections[i].type]||{}).l||'')+'"?'))return;D.sections.splice(i,1);open=new Set();rs();return} if(ds.imv){const[i,j,dir]=ds.imv.split(',').map(Number),arr=D.sections[i][SC[D.sections[i].type].li.k],k=j+dir;if(k<0||k>=arr.length)return;[arr[j],arr[k]]=[arr[k],arr[j]];rs();return} if(ds.irm){const[i,j]=ds.irm.split(',').map(Number);D.sections[i][SC[D.sections[i].type].li.k].splice(j,1);rs();return} if(ds.iadd){const i=+ds.iadd,li=SC[D.sections[i].type].li;(D.sections[i][li.k]=D.sections[i][li.k]||[]).push(clone(li.nw));rs();return} if(ds.up){upload(ds.up);return} if(ds.lib){openLib(ds.lib);return} if(ds.sw){D.theme.accent=ds.sw;rs();return} if(ds.set){const[p,v]=ds.set.split('|');setP(D,p,v);rs();return} if(ds.add){const ty=$('#addSel').value;D.sections.push(clone(NEW[ty]));const n=D.sections.length-1;open=new Set([n]);rs();setTimeout(()=>{const c=$('#sc'+n);c&&c.scrollIntoView({behavior:'smooth'});focusPrev(n)},450);return} if(ds.tg){const i=+ds.tg;if(open.has(i))open.delete(i);else{open=new Set([i]);focusPrev(i)}renderSide();return} }); $('#side').addEventListener('input',e=>{ const p=e.target.dataset.p;if(!p)return;const v=e.target.type==='checkbox'?e.target.checked:e.target.value;setP(D,p,v); const th=e.target.closest('.imgf');if(th)th.querySelector('.th').style.backgroundImage='url("'+String(v).replace(/"/g,'%22')+'")'; const m=p.match(/^sections\.(\d+)\.title$/);if(m){const sm=document.querySelector('#sc'+m[1]+' .sct small');if(sm)sm.textContent=v} if(p==='name'){rec.name=v;$('#rName').value=v} changed(); }); $('#eb').addEventListener('input',e=>{const k=e.target.dataset.r;if(!k||!rec)return;let v=e.target.value;if(k==='price')v=Number(v)||0;rec[k]=v;if(k==='name')D.name=v;changed(k==='name')}); document.querySelectorAll('[data-tab]').forEach(b=>b.onclick=()=>{tab=b.dataset.tab;document.querySelectorAll('[data-tab]').forEach(x=>x.classList.toggle('on',x===b));renderSide()}); document.querySelectorAll('[data-dev]').forEach(b=>b.onclick=()=>{document.querySelectorAll('[data-dev]').forEach(x=>x.classList.toggle('on',x===b));$('#pf').classList.toggle('mob',b.dataset.dev==='mob')}); document.querySelectorAll('[data-pane]').forEach(b=>b.onclick=()=>{document.querySelectorAll('[data-pane]').forEach(x=>x.classList.toggle('on',x===b));$('#ew').classList.toggle('sp',b.dataset.pane==='prev')}); window.addEventListener('message',e=>{const m=e.data||{};if(!m.nx||!D)return; if(m.nx==='sel'){tab='secs';open=new Set([m.i])}else tab='info'; document.querySelectorAll('[data-tab]').forEach(x=>x.classList.toggle('on',x.dataset.tab===tab));renderSide(); if(window.innerWidth<=900){document.querySelectorAll('[data-pane]').forEach(x=>x.classList.toggle('on',x.dataset.pane==='side'));$('#ew').classList.remove('sp')} if(m.nx==='sel'){const c=$('#sc'+m.i);if(c){c.scrollIntoView({behavior:'smooth',block:'start'});c.classList.add('fl');setTimeout(()=>c.classList.remove('fl'),1000);const first=c.querySelector('.in');first&&setTimeout(()=>first.focus({preventScroll:true}),350)}} }); function upload(path,cb){const inp=document.createElement('input');inp.type='file';inp.accept='image/*';inp.onchange=async()=>{const file=inp.files[0];if(!file)return;toast('Enviando imagem…');const fd=new FormData();fd.append('file',file); try{const r=await fetch(P+'/uploads',{method:'POST',body:fd});const j=await r.json();if(!r.ok)throw new Error(j.error||'Falha no envio');setP(D,path,j.url);renderSide();changed();toast('Imagem atualizada ✓');cb&&cb()}catch(e){toast(e.message,true)}};inp.click()} function openLib(path){libPath=path;$('#libUrl').value='';$('#libGrid').innerHTML=LIB.map(u=>``).join('');$('#mLib').classList.add('open')} function useImg(u){if(!libPath||!u)return;setP(D,libPath,u);$('#mLib').classList.remove('open');renderSide();changed();toast('Imagem trocada ✓')} $('#libGrid').addEventListener('click',e=>{const b=e.target.closest('[data-u]');if(b)useImg(b.dataset.u)}); $('#libUse').onclick=()=>{const u=$('#libUrl').value.trim();if(!/^https?:\/\//.test(u)){toast('Cole um link válido começando com https://',true);return}useImg(u)}; document.querySelector('[data-up-lib]').onclick=()=>{const p=libPath;$('#mLib').classList.remove('open');upload(p)}; document.querySelectorAll('.modal').forEach(m=>m.addEventListener('click',e=>{if(e.target===m||e.target.closest('[data-close]'))m.classList.remove('open')})); document.addEventListener('keydown',e=>{if(e.key==='Escape')document.querySelectorAll('.modal.open').forEach(m=>m.classList.remove('open'));if((e.ctrlKey||e.metaKey)&&e.key==='s'){e.preventDefault();save()}}); $('#bSave').onclick=save; $('#bDl').onclick=()=>{if(!D)return;const html=nxRender(D,false),a=document.createElement('a');a.href=URL.createObjectURL(new Blob([html],{type:'text/html'}));a.download=(D.name||'site').normalize('NFD').replace(/[\u0300-\u036f]/g,'').toLowerCase().replace(/[^a-z0-9]+/g,'-').replace(/^-|-$/g,'')+'.html';a.click();toast('HTML baixado — pronto para hospedar ✓')}; $('#bLink').onclick=async()=>{if(!rec)return;const u=location.origin+'/site?id='+rec.id;try{await navigator.clipboard.writeText(u);toast('Link do site copiado ✓')}catch(e){prompt('Copie o link do site:',u)}}; $('#bAi').onclick=()=>{$('#mAi').classList.add('open');setTimeout(()=>$('#aiIns').focus(),50)}; $('#mAi .qch').addEventListener('click',e=>{if(e.target.tagName==='BUTTON')$('#aiIns').value=e.target.textContent}); $('#aiGo').onclick=async()=>{ const ins=$('#aiIns').value.trim()||'Deixe os textos mais premium e persuasivos';const btn=$('#aiGo');btn.disabled=true;btn.textContent='✨ Reescrevendo…'; const texts=D.sections.map(s=>{const o={type:s.type};for(const k in s){const v=s[k];if(['type','image','hidden','map','featured','images'].includes(k))continue;if(typeof v==='string')o[k]=v;else if(Array.isArray(v))o[k]=v.map(it=>{const x={};for(const kk in it)if(typeof it[kk]==='string'&&kk!=='src')x[kk]=it[kk];return x})}return o}); try{ const res=await fetch(P+'/ai',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({system:'Você é um copywriter brasileiro especialista em sites premium. Responda apenas JSON válido.',json:true,max_tokens:4000,messages:[{role:'user',content:'Reescreva os textos do site "'+D.name+'" (nicho: '+(D.niche||'')+') seguindo esta instrução: "'+ins+'".\nRegras: mantenha EXATAMENTE a mesma estrutura JSON, mesmas chaves, mesma quantidade de itens e a mesma ordem; mantenha preços, emojis, números e nomes de pessoas; não aumente o tamanho dos textos.\nResponda só com {"sections":[...]}.\n\n'+JSON.stringify({sections:texts})}]})}); const j=await res.json();if(!res.ok)throw new Error(res.status===429?'Muitas solicitações — tente em um minuto.':(j.error||'IA indisponível')); let o;try{o=JSON.parse(j.text)}catch(e){o=JSON.parse((j.text.match(/\{[\s\S]*\}/)||['{}'])[0])} const out=o.sections||[];let n=0; D.sections.forEach((s,i)=>{const ns=out[i];if(!ns||ns.type!==s.type)return;for(const k in ns){const v=ns[k],ov=s[k]; if(typeof ov==='string'&&typeof v==='string'&&k!=='type'){s[k]=v.slice(0,Math.round(ov.length*1.3)+40);n++} else if(Array.isArray(ov)&&Array.isArray(v))ov.forEach((it,idx)=>{const nv=v[idx];if(!nv||typeof it!=='object')return;for(const kk in nv)if(typeof it[kk]==='string'&&typeof nv[kk]==='string'&&kk!=='src'){it[kk]=nv[kk].slice(0,Math.round(it[kk].length*1.3)+40);n++}})}}); if(!n)throw new Error('A IA não retornou textos válidos. Tente novamente.'); $('#mAi').classList.remove('open');renderSide();changed();toast('✨ '+n+' textos reescritos com IA'); }catch(e){toast(e.message,true)}finally{btn.disabled=false;btn.textContent='Reescrever textos'} }; window.addEventListener('beforeunload',e=>{if(dirty){e.preventDefault();e.returnValue=''}}); async function picker(){ $('#eb').style.display='none';document.querySelector('.mt').style.display='none';document.body.classList.remove('app'); const ew=$('#ew');ew.className='pick';ew.innerHTML='

Editor

Escolha um site para editar ou crie um novo.

Carregando…
'; try{const r=await fetch(API+'/Site?sort=updated_at&order=desc&limit=100');const j=await r.json();if(!r.ok)throw 0;const L=j.records||[]; $('#pkl').innerHTML=L.length?L.map(s=>`${esc(s.name)}${esc(s.niche||'')} · ${esc(s.client||'')}${esc(s.status||'Rascunho')}Editar →`).join(''):'
Nenhum site ainda.

⚡ Criar o primeiro site
'} catch(e){$('#pkl').innerHTML='
Não foi possível carregar a lista de sites.
'} } async function init(){ if(!ID)return picker(); try{rec=await nxGetSite(API,ID)}catch(e){} if(!rec){$('#ew').innerHTML='
Site não encontrado. Voltar ao painel
';setSt('');return} try{D=JSON.parse(rec.data||'{}')}catch(e){D={}} D.sections=Array.isArray(D.sections)?D.sections:[];D.theme=Object.assign({accent:'#00ff84',mode:'dark',font:'moderno',radius:'suave'},D.theme||{}); if(!D.name)D.name=rec.name; $('#rName').value=rec.name||'';$('#rClient').value=rec.client||'';$('#rStatus').value=rec.status||'Rascunho';$('#rPrice').value=rec.price||0; $('#bView').href='/site?id='+rec.id;document.title=(rec.name||'Site')+' — Editor Néxus Word'; renderSide();preview();setSt('✓ Salvo','ok'); } init();