Files
Vula Builder f34ee6c4e8 Deploy
2026-06-04 09:16:58 +00:00

72 lines
4.1 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
(function(){
let enabled=false,overlay=null,badge=null;
function init(){
if(document.getElementById('__vula_ov'))return;
overlay=document.createElement('div');
overlay.id='__vula_ov';
overlay.style.cssText='position:fixed;pointer-events:none;border:2px solid #f97316;border-radius:3px;z-index:999999;transition:top .08s,left .08s,width .08s,height .08s;display:none;box-sizing:border-box;';
badge=document.createElement('div');
badge.id='__vula_badge';
badge.style.cssText='position:fixed;background:#f97316;color:#fff;font:bold 11px/1.4 monospace;padding:3px 8px;border-radius:3px;z-index:1000000;pointer-events:none;display:none;white-space:nowrap;';
document.body.appendChild(overlay);
document.body.appendChild(badge);
}
function cap(s){return s.charAt(0).toUpperCase()+s.slice(1);}
function classify(el){
let sec='',n=el;
while(n&&n!==document.body){
// data-vula-section injected by AICodeValidator post-pass — most reliable source
if(n.dataset&&n.dataset.vulaSection){sec=n.dataset.vulaSection;break;}
const cls=(n.className||'').toString(),tag=n.tagName.toLowerCase();
if(/hero|about|services|contact|team|pricing|faq|gallery|testimonial|footer|header|navigation/i.test(cls)){
sec=cls.split(' ').find(c=>/hero|about|services|contact|team|pricing|faq|gallery|testimonial|footer|header|navigation/i.test(c))||tag;break;
}
if(['section','nav','header','footer'].includes(tag)){sec=tag;break;}
n=n.parentElement;
}
const tag=el.tagName.toLowerCase();
let type='element',label='';
if(tag==='img'){type='image';label=el.alt||'Image';}
else if(tag==='button'||(tag==='a'&&el.href)){type='button';label=(el.textContent||'').trim().slice(0,30)||'Button';}
else if(/^h[1-4]$/.test(tag)){type='heading';label=(el.textContent||'').trim().slice(0,40)||'Heading';}
else if(tag==='p'||tag==='span'){type='text';label=(el.textContent||'').trim().slice(0,40)||'Text';}
else if(tag==='input'||tag==='textarea'){type='input';label=el.placeholder||el.name||'Input';}
else{type='section';label=sec||tag;}
return{section:sec,type,label,tag,className:(el.className||'').toString()};
}
function hl(el){
if(!overlay)return;
const r=el.getBoundingClientRect();
overlay.style.cssText=overlay.style.cssText;
overlay.style.display='block';
overlay.style.top=(r.top-2)+'px';overlay.style.left=(r.left-2)+'px';
overlay.style.width=(r.width+4)+'px';overlay.style.height=(r.height+4)+'px';
const info=classify(el);
badge.style.display='block';
badge.textContent=(info.section?cap(info.section)+' ':'')+info.label;
badge.style.top=Math.max(4,r.top-24)+'px';badge.style.left=r.left+'px';
}
function over(e){if(!enabled)return;e.stopPropagation();init();hl(e.target);}
function sendToParent(msg){
// Works in both iframe (window.parent) and new tab (window.opener)
var t=window.parent!==window?window.parent:(window.opener||null);
if(t)t.postMessage(msg,'*');
}
function click(e){
if(!enabled)return;e.preventDefault();e.stopPropagation();
var info=classify(e.target);
// Use elementType to avoid overwriting the message type field
sendToParent({type:'vula:selected',elementType:info.type,section:info.section,label:info.label,tag:info.tag,className:info.className});
}
function enable(){enabled=true;init();document.addEventListener('mouseover',over,true);document.addEventListener('click',click,true);document.body.style.cursor='crosshair';}
function disable(){enabled=false;document.removeEventListener('mouseover',over,true);document.removeEventListener('click',click,true);document.body.style.cursor='';if(overlay){overlay.style.display='none';badge.style.display='none';}}
window.addEventListener('message',function(e){
if(!e.data)return;
if(e.data.type==='vula:enable')enable();
else if(e.data.type==='vula:disable')disable();
});
// Announce ready so IDE can re-send enable state after iframe reload
function announceReady(){sendToParent({type:'vula:ready'});}
if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',announceReady);}
else{announceReady();}
}());