@accelerated-agency/visual-editor 0.5.3 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/images/cro-sections/cro-cta-block.png +0 -0
- package/dist/images/cro-sections/cro-exit-intent-bar.png +0 -0
- package/dist/images/cro-sections/cro-feature-grid.png +0 -0
- package/dist/images/cro-sections/cro-hero.png +0 -0
- package/dist/images/cro-sections/cro-pricing-table.png +0 -0
- package/dist/images/cro-sections/cro-social-proof.png +0 -0
- package/dist/images/cro-sections/cro-trust-badges.png +0 -0
- package/dist/images/cro-sections/cro-urgency-banner.png +0 -0
- package/dist/index.js +1 -1
- package/dist/vite.cjs +1620 -348
- package/dist/vite.js +1620 -348
- package/package.json +10 -2
- package/src/images/cro-sections/cro-cta-block.png +0 -0
- package/src/images/cro-sections/cro-exit-intent-bar.png +0 -0
- package/src/images/cro-sections/cro-feature-grid.png +0 -0
- package/src/images/cro-sections/cro-hero.png +0 -0
- package/src/images/cro-sections/cro-pricing-table.png +0 -0
- package/src/images/cro-sections/cro-social-proof.png +0 -0
- package/src/images/cro-sections/cro-trust-badges.png +0 -0
- package/src/images/cro-sections/cro-urgency-banner.png +0 -0
package/dist/vite.cjs
CHANGED
|
@@ -11,6 +11,108 @@ var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
|
11
11
|
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
12
12
|
|
|
13
13
|
// src/visualEditorProxyPlugin.ts
|
|
14
|
+
|
|
15
|
+
// src/croSections.ts
|
|
16
|
+
var CRO_SECTION_IMAGE_ROUTE = "/vvveb-editor-images/cro-sections/";
|
|
17
|
+
function croSectionImageFilename(key) {
|
|
18
|
+
return key.replace(/\//g, "-") + ".png";
|
|
19
|
+
}
|
|
20
|
+
var CRO_SECTIONS_BASE = [
|
|
21
|
+
{
|
|
22
|
+
key: "cro/hero",
|
|
23
|
+
name: "CRO Hero",
|
|
24
|
+
icon: "\u{1F3AF}",
|
|
25
|
+
desc: "High-converting hero section",
|
|
26
|
+
html: '<section style="background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);color:white;padding:80px 20px;text-align:center"><div style="max-width:700px;margin:0 auto"><h1 style="font-size:2.8rem;font-weight:800;margin-bottom:16px;color:white">Your Compelling Headline Here</h1><p style="font-size:1.15rem;margin-bottom:28px;opacity:0.9">A clear, benefit-focused subheadline that explains exactly what visitors get from you.</p><a href="#" style="display:inline-block;background:#f59e0b;color:white;padding:16px 40px;border-radius:6px;font-size:1.1rem;font-weight:700;text-decoration:none">Get Started Free →</a><p style="margin-top:14px;font-size:13px;opacity:0.65">✓ No credit card required · ✓ 14-day free trial</p></div></section>'
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
key: "cro/social-proof",
|
|
30
|
+
name: "Social Proof",
|
|
31
|
+
icon: "\u2B50",
|
|
32
|
+
desc: "Star rating + 3-column testimonials",
|
|
33
|
+
html: '<section style="padding:60px 20px;background:#f9fafb"><div style="max-width:1000px;margin:0 auto"><div style="text-align:center;margin-bottom:36px"><div style="font-size:2rem;color:#f59e0b;letter-spacing:4px">★★★★★</div><p style="font-weight:700;font-size:1.2rem;margin-top:4px">4.9 / 5 from 2,400+ verified reviews</p></div><div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:20px"><div style="background:white;border-radius:8px;padding:24px;box-shadow:0 1px 4px rgba(0,0,0,0.08)"><div style="color:#f59e0b;font-size:1.1rem;margin-bottom:10px">★★★★★</div><p style="font-size:14px;color:#444;margin-bottom:16px">"This product completely transformed our results. 40% increase in conversions within the first month."</p><div style="display:flex;align-items:center;gap:10px"><div style="width:36px;height:36px;border-radius:50%;background:#e0e7ff;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:14px">SJ</div><div><div style="font-weight:600;font-size:13px">Sarah Johnson</div><div style="font-size:11px;color:#888">VP Marketing, TechCorp</div></div></div></div><div style="background:white;border-radius:8px;padding:24px;box-shadow:0 1px 4px rgba(0,0,0,0.08)"><div style="color:#f59e0b;font-size:1.1rem;margin-bottom:10px">★★★★★</div><p style="font-size:14px;color:#444;margin-bottom:16px">"The ROI was immediate. Best investment we have made this year. Highly recommend to any serious marketer."</p><div style="display:flex;align-items:center;gap:10px"><div style="width:36px;height:36px;border-radius:50%;background:#dcfce7;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:14px">MC</div><div><div style="font-weight:600;font-size:13px">Mark Chen</div><div style="font-size:11px;color:#888">Founder, GrowthLabs</div></div></div></div><div style="background:white;border-radius:8px;padding:24px;box-shadow:0 1px 4px rgba(0,0,0,0.08)"><div style="color:#f59e0b;font-size:1.1rem;margin-bottom:10px">★★★★★</div><p style="font-size:14px;color:#444;margin-bottom:16px">"Incredible support and the product delivers exactly what it promises. Our entire team loves it."</p><div style="display:flex;align-items:center;gap:10px"><div style="width:36px;height:36px;border-radius:50%;background:#fee2e2;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:14px">AT</div><div><div style="font-weight:600;font-size:13px">Amanda Torres</div><div style="font-size:11px;color:#888">CMO, ScaleUp Inc</div></div></div></div></div></div></section>'
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
key: "cro/urgency-banner",
|
|
37
|
+
name: "Urgency Banner",
|
|
38
|
+
icon: "\u23F0",
|
|
39
|
+
desc: "Countdown timer + limited-time offer",
|
|
40
|
+
html: '<div style="background:#ef4444;color:white;text-align:center;padding:14px;font-size:14px;font-weight:500">🔥 Limited time offer: <strong>50% OFF</strong> ends in <span style="font-family:monospace;font-size:1rem;font-weight:700;background:rgba(0,0,0,0.2);padding:2px 10px;border-radius:4px;margin:0 6px">23:47:12</span>— <a href="#" style="color:white;font-weight:700;text-decoration:underline">Claim your discount →</a></div>'
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
key: "cro/trust-badges",
|
|
44
|
+
name: "Trust Badges",
|
|
45
|
+
icon: "\u{1F6E1}\uFE0F",
|
|
46
|
+
desc: "Security seals, payment icons, guarantees",
|
|
47
|
+
html: '<div style="padding:28px 20px;border-top:1px solid #e5e5e5;border-bottom:1px solid #e5e5e5;background:white"><div style="display:flex;flex-wrap:wrap;justify-content:center;align-items:center;gap:32px;max-width:700px;margin:0 auto"><div style="text-align:center;font-size:12px;color:#555"><div style="font-size:28px;margin-bottom:6px">🔒</div><div style="font-weight:600">SSL Secure</div><div style="font-size:10px;color:#888">256-bit encryption</div></div><div style="text-align:center;font-size:12px;color:#555"><div style="font-size:28px;margin-bottom:6px">↵</div><div style="font-weight:600">30-Day Guarantee</div><div style="font-size:10px;color:#888">Money back, no questions</div></div><div style="text-align:center;font-size:12px;color:#555"><div style="font-size:28px;margin-bottom:6px">⭐</div><div style="font-weight:600">4.9 / 5 Rating</div><div style="font-size:10px;color:#888">From 2,400+ reviews</div></div><div style="text-align:center;font-size:12px;color:#555"><div style="font-size:28px;margin-bottom:6px">💳</div><div style="font-weight:600">Secure Payment</div><div style="font-size:10px;color:#888">Visa · MC · PayPal</div></div></div></div>'
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
key: "cro/cta-block",
|
|
51
|
+
name: "CTA Block",
|
|
52
|
+
icon: "\u{1F4E3}",
|
|
53
|
+
desc: "Dark high-impact call-to-action section",
|
|
54
|
+
html: '<section style="background:#1a1a2e;color:white;padding:64px 20px;text-align:center"><div style="max-width:600px;margin:0 auto"><h2 style="font-size:2rem;font-weight:800;color:white;margin-bottom:10px">Ready to get started?</h2><p style="opacity:0.7;margin-bottom:32px">Join 10,000+ companies already seeing results with our platform.</p><div style="display:flex;gap:12px;justify-content:center;flex-wrap:wrap"><a href="#" style="display:inline-block;background:#f59e0b;color:white;padding:14px 36px;border-radius:6px;font-weight:700;text-decoration:none;font-size:1rem">Start Free Trial</a><a href="#" style="display:inline-block;border:2px solid rgba(255,255,255,0.4);color:white;padding:14px 36px;border-radius:6px;font-weight:600;text-decoration:none;font-size:1rem">Schedule Demo</a></div><p style="font-size:12px;margin-top:18px;opacity:0.45">No credit card required · Cancel anytime</p></div></section>'
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
key: "cro/feature-grid",
|
|
58
|
+
name: "Feature Grid",
|
|
59
|
+
icon: "\u2728",
|
|
60
|
+
desc: "3-column key benefits grid",
|
|
61
|
+
html: '<section style="padding:60px 20px;background:white"><div style="max-width:900px;margin:0 auto"><h2 style="text-align:center;font-size:1.8rem;font-weight:800;margin-bottom:48px">Why choose us?</h2><div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:32px;text-align:center"><div><div style="font-size:2.5rem;margin-bottom:14px">🚀</div><h5 style="font-weight:700;margin-bottom:8px">Fast Results</h5><p style="color:#666;font-size:14px">See improvements in your conversion rate within the first 30 days or your money back.</p></div><div><div style="font-size:2.5rem;margin-bottom:14px">📊</div><h5 style="font-weight:700;margin-bottom:8px">Data-Driven</h5><p style="color:#666;font-size:14px">Every decision backed by real user data and statistical significance testing.</p></div><div><div style="font-size:2.5rem;margin-bottom:14px">🎯</div><h5 style="font-weight:700;margin-bottom:8px">Precision Targeting</h5><p style="color:#666;font-size:14px">Target the right audience segments with personalized, high-converting experiences.</p></div></div></div></section>'
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
key: "cro/exit-intent-bar",
|
|
65
|
+
name: "Exit Intent Bar",
|
|
66
|
+
icon: "\u{1F6AA}",
|
|
67
|
+
desc: "Sticky bottom bar for exit-intent capture",
|
|
68
|
+
html: `<div style="position:fixed;bottom:0;left:0;right:0;background:#1e293b;color:white;padding:14px 20px;display:flex;align-items:center;justify-content:center;gap:16px;z-index:9999;box-shadow:0 -4px 20px rgba(0,0,0,0.2)"><span style="font-size:14px">🔔 <strong>Wait!</strong> Don't leave empty-handed — get 20% off your first order.</span><a href="#" style="background:#f59e0b;color:white;padding:8px 20px;border-radius:4px;font-weight:700;text-decoration:none;font-size:13px;white-space:nowrap">Claim Offer</a><a href="#" style="color:rgba(255,255,255,0.5);font-size:12px;text-decoration:none">No thanks</a></div>`
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
key: "cro/pricing-table",
|
|
72
|
+
name: "Pricing Table",
|
|
73
|
+
icon: "\u{1F4B0}",
|
|
74
|
+
desc: "3-tier pricing with highlighted plan",
|
|
75
|
+
html: '<section style="padding:60px 20px;background:#f8fafc"><div style="max-width:900px;margin:0 auto"><h2 style="text-align:center;font-weight:800;font-size:1.8rem;margin-bottom:8px">Simple, transparent pricing</h2><p style="text-align:center;color:#666;margin-bottom:48px">No hidden fees. Cancel anytime.</p><div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:20px"><div style="background:white;border:1px solid #e5e5e5;border-radius:10px;padding:28px"><h3 style="font-weight:700;margin-bottom:6px">Starter</h3><div style="font-size:2rem;font-weight:800;margin-bottom:16px">$29<span style="font-size:1rem;font-weight:400;color:#888">/mo</span></div><ul style="list-style:none;padding:0;font-size:14px;color:#555;margin-bottom:24px"><li style="padding:6px 0;border-bottom:1px solid #f0f0f0">✓ Up to 10,000 visitors/mo</li><li style="padding:6px 0;border-bottom:1px solid #f0f0f0">✓ 5 A/B tests</li><li style="padding:6px 0">✓ Email support</li></ul><a href="#" style="display:block;text-align:center;border:2px solid #e5e5e5;padding:10px;border-radius:6px;font-weight:600;text-decoration:none;color:#333">Get started</a></div><div style="background:#3b82f6;border-radius:10px;padding:28px;position:relative;transform:scale(1.04);box-shadow:0 8px 32px rgba(59,130,246,0.3)"><div style="position:absolute;top:-12px;left:50%;transform:translateX(-50%);background:#f59e0b;color:white;font-size:11px;font-weight:700;padding:4px 12px;border-radius:20px">MOST POPULAR</div><h3 style="font-weight:700;margin-bottom:6px;color:white">Pro</h3><div style="font-size:2rem;font-weight:800;margin-bottom:16px;color:white">$79<span style="font-size:1rem;font-weight:400;opacity:0.7">/mo</span></div><ul style="list-style:none;padding:0;font-size:14px;color:rgba(255,255,255,0.85);margin-bottom:24px"><li style="padding:6px 0;border-bottom:1px solid rgba(255,255,255,0.15)">✓ Up to 100,000 visitors/mo</li><li style="padding:6px 0;border-bottom:1px solid rgba(255,255,255,0.15)">✓ Unlimited A/B tests</li><li style="padding:6px 0">✓ Priority support</li></ul><a href="#" style="display:block;text-align:center;background:white;color:#3b82f6;padding:10px;border-radius:6px;font-weight:700;text-decoration:none">Get started</a></div><div style="background:white;border:1px solid #e5e5e5;border-radius:10px;padding:28px"><h3 style="font-weight:700;margin-bottom:6px">Enterprise</h3><div style="font-size:2rem;font-weight:800;margin-bottom:16px">Custom</div><ul style="list-style:none;padding:0;font-size:14px;color:#555;margin-bottom:24px"><li style="padding:6px 0;border-bottom:1px solid #f0f0f0">✓ Unlimited visitors</li><li style="padding:6px 0;border-bottom:1px solid #f0f0f0">✓ White-label option</li><li style="padding:6px 0">✓ Dedicated support</li></ul><a href="#" style="display:block;text-align:center;border:2px solid #e5e5e5;padding:10px;border-radius:6px;font-weight:600;text-decoration:none;color:#333">Contact sales</a></div></div></div></section>'
|
|
76
|
+
}
|
|
77
|
+
];
|
|
78
|
+
var CRO_SECTIONS = CRO_SECTIONS_BASE.map((section) => ({
|
|
79
|
+
...section,
|
|
80
|
+
image: croSectionImageFilename(section.key)
|
|
81
|
+
}));
|
|
82
|
+
|
|
83
|
+
// src/visualEditorProxyPlugin.ts
|
|
84
|
+
var PACKAGE_ROOT = path__default.default.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('vite.cjs', document.baseURI).href))));
|
|
85
|
+
function resolveCroSectionImagePath(filename) {
|
|
86
|
+
const safe = path__default.default.basename(filename);
|
|
87
|
+
if (!safe || safe !== filename) return null;
|
|
88
|
+
const candidates = [
|
|
89
|
+
path__default.default.join(PACKAGE_ROOT, "images", "cro-sections", safe),
|
|
90
|
+
path__default.default.join(PACKAGE_ROOT, "..", "src", "images", "cro-sections", safe),
|
|
91
|
+
path__default.default.join(process.cwd(), "src", "images", "cro-sections", safe)
|
|
92
|
+
];
|
|
93
|
+
for (const candidate of candidates) {
|
|
94
|
+
try {
|
|
95
|
+
if (fs__default.default.existsSync(candidate)) return candidate;
|
|
96
|
+
} catch (_) {
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
function listCroSectionImageFiles() {
|
|
102
|
+
const dirs = [
|
|
103
|
+
path__default.default.join(PACKAGE_ROOT, "images", "cro-sections"),
|
|
104
|
+
path__default.default.join(PACKAGE_ROOT, "..", "src", "images", "cro-sections"),
|
|
105
|
+
path__default.default.join(process.cwd(), "src", "images", "cro-sections")
|
|
106
|
+
];
|
|
107
|
+
for (const dir of dirs) {
|
|
108
|
+
try {
|
|
109
|
+
if (!fs__default.default.existsSync(dir)) continue;
|
|
110
|
+
return fs__default.default.readdirSync(dir).filter((name) => name.endsWith(".png")).map((name) => path__default.default.join(dir, name));
|
|
111
|
+
} catch (_) {
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return [];
|
|
115
|
+
}
|
|
14
116
|
var DEFAULT_TRACKING_MARKERS = [
|
|
15
117
|
"snowplow",
|
|
16
118
|
"taboola",
|
|
@@ -262,64 +364,6 @@ catch(_){}})();</script>`;
|
|
|
262
364
|
var AI_SYSTEM_PROMPT = `You are a CRO expert. Return JSON only with: hypothesis, mutations, summary. Keep 2-6 precise mutations and only valid selectors from snapshot.`;
|
|
263
365
|
var BRIDGE_SCRIPT = `(function(){if(window.__CONVERSION_BRIDGE_LOADED__)return;window.__CONVERSION_BRIDGE_LOADED__=true;var CHANNEL='conversion-editor';var highlightEl=null;function send(payload){window.parent.postMessage({channel:CHANNEL,payload:payload},'*');}function qs(selector){try{return document.querySelector(selector);}catch(_){return null;}}function getSelector(el){if(!el||el.nodeType!==1)return'';if(el.id)return'#'+CSS.escape(el.id);var parts=[];var current=el;var depth=0;while(current&¤t.nodeType===1&&depth<5){var part=current.tagName.toLowerCase();if(current.classList&¤t.classList.length){part+='.'+Array.from(current.classList).slice(0,2).map(function(c){return CSS.escape(c);}).join('.');}var parent=current.parentElement;if(parent){var siblings=Array.from(parent.children).filter(function(s){return s.tagName===current.tagName;});if(siblings.length>1)part+=':nth-of-type('+(siblings.indexOf(current)+1)+')';}parts.unshift(part);current=parent;depth+=1;}return parts.join(' > ');}function payloadOf(el){var rect=el.getBoundingClientRect();var style=window.getComputedStyle(el);return{selector:getSelector(el),tagName:el.tagName.toLowerCase(),textContent:(el.textContent||'').trim().slice(0,500),computedStyles:{color:style.color,backgroundColor:style.backgroundColor,fontSize:style.fontSize,fontWeight:style.fontWeight,lineHeight:style.lineHeight,display:style.display},rect:{top:rect.top,left:rect.left,width:rect.width,height:rect.height}};}function applyMutation(m){var el=qs(m.selector);if(!el)return;switch(m.action){case'setStyle':if(m.property)el.style[m.property]=m.value;break;case'setText':el.textContent=m.value;break;case'setHTML':el.innerHTML=m.value;break;case'setAttribute':if(m.property)el.setAttribute(m.property,m.value);break;case'hide':el.style.display='none';break;case'show':el.style.display='';break;case'insertHTML':if(m.position)el.insertAdjacentHTML(m.position,m.value||'');break;case'insertSection':if(m.position)el.insertAdjacentHTML(m.position,m.sectionHtml||m.value||'');break;case'reorderElement':if(!m.targetSelector)break;var target=qs(m.targetSelector);if(!target||!target.parentNode||!el.parentNode)break;if(m.insertPosition==='before')target.parentNode.insertBefore(el,target);else target.parentNode.insertBefore(el,target.nextSibling);break;default:break;}}function revertMutation(m){var el=qs(m.selector);if(!el)return;switch(m.action){case'setStyle':if(m.property)el.style[m.property]=m.previous||'';break;case'setText':el.textContent=m.previous||'';break;case'setHTML':el.innerHTML=m.previous||'';break;case'setAttribute':if(m.property){if(m.previous!=null)el.setAttribute(m.property,m.previous);else el.removeAttribute(m.property);}break;case'hide':case'show':el.style.display=m.previous||'';break;default:break;}}function captureSnapshot(){var elements=Array.from(document.querySelectorAll('h1,h2,h3,p,button,a,input,select,img,section,div')).slice(0,700).map(function(el){var rect=el.getBoundingClientRect();var cs=window.getComputedStyle(el);return{selector:getSelector(el),parentSelector:el.parentElement?getSelector(el.parentElement):null,tagName:el.tagName.toLowerCase(),textContent:(el.textContent||'').trim().slice(0,300),attributes:Array.from(el.attributes||[]).reduce(function(acc,a){acc[a.name]=a.value;return acc;},{}),computedStyles:{color:cs.color,backgroundColor:cs.backgroundColor,fontSize:cs.fontSize,fontWeight:cs.fontWeight,display:cs.display},childrenCount:el.children?el.children.length:0,aboveFold:rect.top<window.innerHeight,depth:(function(){var d=0,p=el.parentElement;while(p&&d<25){d++;p=p.parentElement;}return d;})()};});send({type:'snapshotCaptured',snapshot:{url:window.location.href,title:document.title,viewport:{width:window.innerWidth,height:window.innerHeight},elements:elements}});}function captureTree(){function toNode(el,depth){var rect=el.getBoundingClientRect();var tag=el.tagName.toLowerCase();var type='generic';if(tag==='section')type='section';else if(tag==='img')type='image';else if(tag==='a')type='link';else if(tag==='button')type='button';else if(tag==='form')type='form';else if(['p','h1','h2','h3','h4','h5','h6','span'].indexOf(tag)>=0)type='text';else if(['div','main','article','aside','header','footer','nav'].indexOf(tag)>=0)type='container';var children=Array.from(el.children||[]).slice(0,50).map(function(c){return toNode(c,depth+1);});return{id:getSelector(el),selector:getSelector(el),tagName:tag,label:(el.getAttribute('aria-label')||el.getAttribute('id')||el.className||tag).toString().slice(0,80),type:type,children:children,depth:depth,isAboveFold:rect.top<window.innerHeight,rect:{top:rect.top,left:rect.left,width:rect.width,height:rect.height}};}send({type:'pageTreeCaptured',tree:[toNode(document.body,0)]});}window.addEventListener('message',function(e){var msg=e.data;if(!msg||msg.channel!==CHANNEL||!msg.payload)return;var p=msg.payload;switch(p.type){case'ping':send({type:'pong'});break;case'applyMutation':applyMutation(p.mutation);break;case'applyMutationBatch':(p.mutations||[]).forEach(applyMutation);break;case'revert':revertMutation(p.mutation);break;case'clearAllMutations':window.location.reload();break;case'captureSnapshot':captureSnapshot();break;case'validateSelectors':send({type:'selectorsValidated',results:(p.selectors||[]).map(function(s){var el=qs(s);return{selector:s,found:!!el,tagName:el?el.tagName.toLowerCase():null};})});break;case'scrollToElement':case'selectElement':var target=qs(p.selector);if(target){target.scrollIntoView({behavior:'smooth',block:'center'});send({type:'elementSelected',element:payloadOf(target)});}break;case'hoverElement':var h=qs(p.selector);if(h){if(highlightEl)highlightEl.style.outline='';h.style.outline='2px solid #3b82f6';highlightEl=h;}break;case'capturePageTree':captureTree();break;default:break;}});document.addEventListener('click',function(e){var el=e.target;if(!(el instanceof Element))return;send({type:'elementSelected',element:payloadOf(el)});},true);send({type:'bridgeReady'});})();`;
|
|
264
366
|
function buildVvvebEditorHtml() {
|
|
265
|
-
const CRO_SECTIONS = [
|
|
266
|
-
{
|
|
267
|
-
key: "cro/hero",
|
|
268
|
-
name: "CRO Hero",
|
|
269
|
-
icon: "\u{1F3AF}",
|
|
270
|
-
desc: "High-converting hero section",
|
|
271
|
-
html: '<section style="background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);color:white;padding:80px 20px;text-align:center"><div style="max-width:700px;margin:0 auto"><h1 style="font-size:2.8rem;font-weight:800;margin-bottom:16px;color:white">Your Compelling Headline Here</h1><p style="font-size:1.15rem;margin-bottom:28px;opacity:0.9">A clear, benefit-focused subheadline that explains exactly what visitors get from you.</p><a href="#" style="display:inline-block;background:#f59e0b;color:white;padding:16px 40px;border-radius:6px;font-size:1.1rem;font-weight:700;text-decoration:none">Get Started Free →</a><p style="margin-top:14px;font-size:13px;opacity:0.65">✓ No credit card required · ✓ 14-day free trial</p></div></section>'
|
|
272
|
-
},
|
|
273
|
-
{
|
|
274
|
-
key: "cro/social-proof",
|
|
275
|
-
name: "Social Proof",
|
|
276
|
-
icon: "\u2B50",
|
|
277
|
-
desc: "Star rating + 3-column testimonials",
|
|
278
|
-
html: '<section style="padding:60px 20px;background:#f9fafb"><div style="max-width:1000px;margin:0 auto"><div style="text-align:center;margin-bottom:36px"><div style="font-size:2rem;color:#f59e0b;letter-spacing:4px">★★★★★</div><p style="font-weight:700;font-size:1.2rem;margin-top:4px">4.9 / 5 from 2,400+ verified reviews</p></div><div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:20px"><div style="background:white;border-radius:8px;padding:24px;box-shadow:0 1px 4px rgba(0,0,0,0.08)"><div style="color:#f59e0b;font-size:1.1rem;margin-bottom:10px">★★★★★</div><p style="font-size:14px;color:#444;margin-bottom:16px">"This product completely transformed our results. 40% increase in conversions within the first month."</p><div style="display:flex;align-items:center;gap:10px"><div style="width:36px;height:36px;border-radius:50%;background:#e0e7ff;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:14px">SJ</div><div><div style="font-weight:600;font-size:13px">Sarah Johnson</div><div style="font-size:11px;color:#888">VP Marketing, TechCorp</div></div></div></div><div style="background:white;border-radius:8px;padding:24px;box-shadow:0 1px 4px rgba(0,0,0,0.08)"><div style="color:#f59e0b;font-size:1.1rem;margin-bottom:10px">★★★★★</div><p style="font-size:14px;color:#444;margin-bottom:16px">"The ROI was immediate. Best investment we have made this year. Highly recommend to any serious marketer."</p><div style="display:flex;align-items:center;gap:10px"><div style="width:36px;height:36px;border-radius:50%;background:#dcfce7;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:14px">MC</div><div><div style="font-weight:600;font-size:13px">Mark Chen</div><div style="font-size:11px;color:#888">Founder, GrowthLabs</div></div></div></div><div style="background:white;border-radius:8px;padding:24px;box-shadow:0 1px 4px rgba(0,0,0,0.08)"><div style="color:#f59e0b;font-size:1.1rem;margin-bottom:10px">★★★★★</div><p style="font-size:14px;color:#444;margin-bottom:16px">"Incredible support and the product delivers exactly what it promises. Our entire team loves it."</p><div style="display:flex;align-items:center;gap:10px"><div style="width:36px;height:36px;border-radius:50%;background:#fee2e2;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:14px">AT</div><div><div style="font-weight:600;font-size:13px">Amanda Torres</div><div style="font-size:11px;color:#888">CMO, ScaleUp Inc</div></div></div></div></div></div></section>'
|
|
279
|
-
},
|
|
280
|
-
{
|
|
281
|
-
key: "cro/urgency-banner",
|
|
282
|
-
name: "Urgency Banner",
|
|
283
|
-
icon: "\u23F0",
|
|
284
|
-
desc: "Countdown timer + limited-time offer",
|
|
285
|
-
html: '<div style="background:#ef4444;color:white;text-align:center;padding:14px;font-size:14px;font-weight:500">🔥 Limited time offer: <strong>50% OFF</strong> ends in <span style="font-family:monospace;font-size:1rem;font-weight:700;background:rgba(0,0,0,0.2);padding:2px 10px;border-radius:4px;margin:0 6px">23:47:12</span>— <a href="#" style="color:white;font-weight:700;text-decoration:underline">Claim your discount →</a></div>'
|
|
286
|
-
},
|
|
287
|
-
{
|
|
288
|
-
key: "cro/trust-badges",
|
|
289
|
-
name: "Trust Badges",
|
|
290
|
-
icon: "\u{1F6E1}\uFE0F",
|
|
291
|
-
desc: "Security seals, payment icons, guarantees",
|
|
292
|
-
html: '<div style="padding:28px 20px;border-top:1px solid #e5e5e5;border-bottom:1px solid #e5e5e5;background:white"><div style="display:flex;flex-wrap:wrap;justify-content:center;align-items:center;gap:32px;max-width:700px;margin:0 auto"><div style="text-align:center;font-size:12px;color:#555"><div style="font-size:28px;margin-bottom:6px">🔒</div><div style="font-weight:600">SSL Secure</div><div style="font-size:10px;color:#888">256-bit encryption</div></div><div style="text-align:center;font-size:12px;color:#555"><div style="font-size:28px;margin-bottom:6px">↵</div><div style="font-weight:600">30-Day Guarantee</div><div style="font-size:10px;color:#888">Money back, no questions</div></div><div style="text-align:center;font-size:12px;color:#555"><div style="font-size:28px;margin-bottom:6px">⭐</div><div style="font-weight:600">4.9 / 5 Rating</div><div style="font-size:10px;color:#888">From 2,400+ reviews</div></div><div style="text-align:center;font-size:12px;color:#555"><div style="font-size:28px;margin-bottom:6px">💳</div><div style="font-weight:600">Secure Payment</div><div style="font-size:10px;color:#888">Visa · MC · PayPal</div></div></div></div>'
|
|
293
|
-
},
|
|
294
|
-
{
|
|
295
|
-
key: "cro/cta-block",
|
|
296
|
-
name: "CTA Block",
|
|
297
|
-
icon: "\u{1F4E3}",
|
|
298
|
-
desc: "Dark high-impact call-to-action section",
|
|
299
|
-
html: '<section style="background:#1a1a2e;color:white;padding:64px 20px;text-align:center"><div style="max-width:600px;margin:0 auto"><h2 style="font-size:2rem;font-weight:800;color:white;margin-bottom:10px">Ready to get started?</h2><p style="opacity:0.7;margin-bottom:32px">Join 10,000+ companies already seeing results with our platform.</p><div style="display:flex;gap:12px;justify-content:center;flex-wrap:wrap"><a href="#" style="display:inline-block;background:#f59e0b;color:white;padding:14px 36px;border-radius:6px;font-weight:700;text-decoration:none;font-size:1rem">Start Free Trial</a><a href="#" style="display:inline-block;border:2px solid rgba(255,255,255,0.4);color:white;padding:14px 36px;border-radius:6px;font-weight:600;text-decoration:none;font-size:1rem">Schedule Demo</a></div><p style="font-size:12px;margin-top:18px;opacity:0.45">No credit card required · Cancel anytime</p></div></section>'
|
|
300
|
-
},
|
|
301
|
-
{
|
|
302
|
-
key: "cro/feature-grid",
|
|
303
|
-
name: "Feature Grid",
|
|
304
|
-
icon: "\u2728",
|
|
305
|
-
desc: "3-column key benefits grid",
|
|
306
|
-
html: '<section style="padding:60px 20px;background:white"><div style="max-width:900px;margin:0 auto"><h2 style="text-align:center;font-size:1.8rem;font-weight:800;margin-bottom:48px">Why choose us?</h2><div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:32px;text-align:center"><div><div style="font-size:2.5rem;margin-bottom:14px">🚀</div><h5 style="font-weight:700;margin-bottom:8px">Fast Results</h5><p style="color:#666;font-size:14px">See improvements in your conversion rate within the first 30 days or your money back.</p></div><div><div style="font-size:2.5rem;margin-bottom:14px">📊</div><h5 style="font-weight:700;margin-bottom:8px">Data-Driven</h5><p style="color:#666;font-size:14px">Every decision backed by real user data and statistical significance testing.</p></div><div><div style="font-size:2.5rem;margin-bottom:14px">🎯</div><h5 style="font-weight:700;margin-bottom:8px">Precision Targeting</h5><p style="color:#666;font-size:14px">Target the right audience segments with personalized, high-converting experiences.</p></div></div></div></section>'
|
|
307
|
-
},
|
|
308
|
-
{
|
|
309
|
-
key: "cro/exit-intent-bar",
|
|
310
|
-
name: "Exit Intent Bar",
|
|
311
|
-
icon: "\u{1F6AA}",
|
|
312
|
-
desc: "Sticky bottom bar for exit-intent capture",
|
|
313
|
-
html: `<div style="position:fixed;bottom:0;left:0;right:0;background:#1e293b;color:white;padding:14px 20px;display:flex;align-items:center;justify-content:center;gap:16px;z-index:9999;box-shadow:0 -4px 20px rgba(0,0,0,0.2)"><span style="font-size:14px">🔔 <strong>Wait!</strong> Don't leave empty-handed — get 20% off your first order.</span><a href="#" style="background:#f59e0b;color:white;padding:8px 20px;border-radius:4px;font-weight:700;text-decoration:none;font-size:13px;white-space:nowrap">Claim Offer</a><a href="#" style="color:rgba(255,255,255,0.5);font-size:12px;text-decoration:none">No thanks</a></div>`
|
|
314
|
-
},
|
|
315
|
-
{
|
|
316
|
-
key: "cro/pricing-table",
|
|
317
|
-
name: "Pricing Table",
|
|
318
|
-
icon: "\u{1F4B0}",
|
|
319
|
-
desc: "3-tier pricing with highlighted plan",
|
|
320
|
-
html: '<section style="padding:60px 20px;background:#f8fafc"><div style="max-width:900px;margin:0 auto"><h2 style="text-align:center;font-weight:800;font-size:1.8rem;margin-bottom:8px">Simple, transparent pricing</h2><p style="text-align:center;color:#666;margin-bottom:48px">No hidden fees. Cancel anytime.</p><div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:20px"><div style="background:white;border:1px solid #e5e5e5;border-radius:10px;padding:28px"><h3 style="font-weight:700;margin-bottom:6px">Starter</h3><div style="font-size:2rem;font-weight:800;margin-bottom:16px">$29<span style="font-size:1rem;font-weight:400;color:#888">/mo</span></div><ul style="list-style:none;padding:0;font-size:14px;color:#555;margin-bottom:24px"><li style="padding:6px 0;border-bottom:1px solid #f0f0f0">✓ Up to 10,000 visitors/mo</li><li style="padding:6px 0;border-bottom:1px solid #f0f0f0">✓ 5 A/B tests</li><li style="padding:6px 0">✓ Email support</li></ul><a href="#" style="display:block;text-align:center;border:2px solid #e5e5e5;padding:10px;border-radius:6px;font-weight:600;text-decoration:none;color:#333">Get started</a></div><div style="background:#3b82f6;border-radius:10px;padding:28px;position:relative;transform:scale(1.04);box-shadow:0 8px 32px rgba(59,130,246,0.3)"><div style="position:absolute;top:-12px;left:50%;transform:translateX(-50%);background:#f59e0b;color:white;font-size:11px;font-weight:700;padding:4px 12px;border-radius:20px">MOST POPULAR</div><h3 style="font-weight:700;margin-bottom:6px;color:white">Pro</h3><div style="font-size:2rem;font-weight:800;margin-bottom:16px;color:white">$79<span style="font-size:1rem;font-weight:400;opacity:0.7">/mo</span></div><ul style="list-style:none;padding:0;font-size:14px;color:rgba(255,255,255,0.85);margin-bottom:24px"><li style="padding:6px 0;border-bottom:1px solid rgba(255,255,255,0.15)">✓ Up to 100,000 visitors/mo</li><li style="padding:6px 0;border-bottom:1px solid rgba(255,255,255,0.15)">✓ Unlimited A/B tests</li><li style="padding:6px 0">✓ Priority support</li></ul><a href="#" style="display:block;text-align:center;background:white;color:#3b82f6;padding:10px;border-radius:6px;font-weight:700;text-decoration:none">Get started</a></div><div style="background:white;border:1px solid #e5e5e5;border-radius:10px;padding:28px"><h3 style="font-weight:700;margin-bottom:6px">Enterprise</h3><div style="font-size:2rem;font-weight:800;margin-bottom:16px">Custom</div><ul style="list-style:none;padding:0;font-size:14px;color:#555;margin-bottom:24px"><li style="padding:6px 0;border-bottom:1px solid #f0f0f0">✓ Unlimited visitors</li><li style="padding:6px 0;border-bottom:1px solid #f0f0f0">✓ White-label option</li><li style="padding:6px 0">✓ Dedicated support</li></ul><a href="#" style="display:block;text-align:center;border:2px solid #e5e5e5;padding:10px;border-radius:6px;font-weight:600;text-decoration:none;color:#333">Contact sales</a></div></div></div></section>'
|
|
321
|
-
}
|
|
322
|
-
];
|
|
323
367
|
const sectionsJson = JSON.stringify(CRO_SECTIONS);
|
|
324
368
|
return `<!DOCTYPE html>
|
|
325
369
|
<html lang="en">
|
|
@@ -327,27 +371,39 @@ function buildVvvebEditorHtml() {
|
|
|
327
371
|
<meta charset="UTF-8">
|
|
328
372
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
329
373
|
<title>Visual Editor V2</title>
|
|
374
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
375
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
376
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">
|
|
330
377
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
|
331
378
|
<style>
|
|
332
379
|
/* \u2500\u2500 Reset \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
333
380
|
*{box-sizing:border-box;margin:0;padding:0}
|
|
334
|
-
html,body{height:100%;overflow:hidden;font-family
|
|
381
|
+
html,body{height:100%;overflow:hidden;font-family:var(--font-sans);font-size:13px;color:#1e293b;background:#f1f5f9}
|
|
335
382
|
|
|
336
383
|
/* \u2500\u2500 CSS variables \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
337
384
|
:root{
|
|
385
|
+
--font-inter:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
|
|
386
|
+
--font-roboto:'Roboto',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
|
|
387
|
+
--font-mono:'JetBrains Mono',ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;
|
|
388
|
+
--font-sans:var(--font-inter),var(--font-roboto),-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
|
|
338
389
|
--bg: #ffffff;
|
|
339
390
|
--bg-sub: #f8fafc;
|
|
340
|
-
--bg-hover: #
|
|
391
|
+
--bg-hover: #F5F5F5;
|
|
341
392
|
--border: #e2e8f0;
|
|
342
393
|
--border-sub: #f1f5f9;
|
|
343
394
|
--text: #404040;
|
|
344
395
|
--text-2: #475569;
|
|
345
396
|
--text-3: #94a3b8;
|
|
346
|
-
--accent: #
|
|
347
|
-
--accent-bg: #
|
|
397
|
+
--accent: #262626;
|
|
398
|
+
--accent-bg: #f5f5f5;
|
|
348
399
|
--accent-txt: #404040;
|
|
349
400
|
}
|
|
350
401
|
|
|
402
|
+
/* \u2500\u2500 Font utilities \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
403
|
+
.inter{font-family:var(--font-inter)}
|
|
404
|
+
.roboto{font-family:var(--font-roboto)}
|
|
405
|
+
.mono{font-family:var(--font-mono)}
|
|
406
|
+
|
|
351
407
|
/* \u2500\u2500 Layout \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
352
408
|
#app{display:flex;flex-direction:column;height:100vh}
|
|
353
409
|
#main{display:flex;flex:1;overflow:hidden;min-height:0}
|
|
@@ -425,9 +481,32 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
425
481
|
border-color:transparent;
|
|
426
482
|
}
|
|
427
483
|
.tb-dev-menu input#dev-zoom-level{
|
|
428
|
-
max-width:
|
|
429
|
-
margin-left:
|
|
484
|
+
max-width:72px;
|
|
485
|
+
margin-left:0;
|
|
430
486
|
}
|
|
487
|
+
.tb-dev-menu .row-zoom .zoom-controls{
|
|
488
|
+
display:flex;
|
|
489
|
+
align-items:center;
|
|
490
|
+
gap:6px;
|
|
491
|
+
margin-left:auto;
|
|
492
|
+
}
|
|
493
|
+
.tb-dev-menu .dev-zoom-fit-btn{
|
|
494
|
+
width:30px;
|
|
495
|
+
height:30px;
|
|
496
|
+
flex-shrink:0;
|
|
497
|
+
border:none;
|
|
498
|
+
border-radius:6px;
|
|
499
|
+
background:#fff;
|
|
500
|
+
cursor:pointer;
|
|
501
|
+
display:flex;
|
|
502
|
+
align-items:center;
|
|
503
|
+
justify-content:center;
|
|
504
|
+
color:#404040;
|
|
505
|
+
box-shadow:0 0 1px 0 rgba(0,0,0,.20),0 1px 2px 0 rgba(0,0,0,.05),0 1px 1px 0 rgba(0,0,0,.01);
|
|
506
|
+
transition:background .12s,color .12s;
|
|
507
|
+
}
|
|
508
|
+
.tb-dev-menu .dev-zoom-fit-btn:hover{background:#f4f4f5;color:#171717}
|
|
509
|
+
.tb-dev-menu .dev-zoom-fit-btn svg{display:block;width:16px;height:16px}
|
|
431
510
|
.tb-dev-menu input:focus{
|
|
432
511
|
border-color:#1A1A1A;
|
|
433
512
|
box-shadow:0 0 0 2px rgba(99,102,241,.14)
|
|
@@ -457,19 +536,10 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
457
536
|
text-overflow: ellipsis;
|
|
458
537
|
font-size: var(--font-size-sm, 14px);
|
|
459
538
|
font-style: normal;
|
|
460
|
-
font-weight: 500
|
|
539
|
+
font-weight: 500;#
|
|
461
540
|
line-height: var(--font-leading-4, 16px);
|
|
462
541
|
}
|
|
463
542
|
.tb-dev-menu .vp-preset-btn:hover,.tb-dev-menu .vp-preset-btn.active{background:#f4f4f5}
|
|
464
|
-
.tb-dev-menu .ft{
|
|
465
|
-
margin-top:10px;padding-top:8px;border-top:1px solid #ececf0;
|
|
466
|
-
display:flex;justify-content:flex-end
|
|
467
|
-
}
|
|
468
|
-
.tb-dev-menu .apply-btn{
|
|
469
|
-
border:1px solid #d4d4d8;background:#f8fafc;color:#111827;border-radius:6px;
|
|
470
|
-
height:30px;padding:0 10px;font-size:12px;font-weight:600;cursor:pointer
|
|
471
|
-
}
|
|
472
|
-
.tb-dev-menu .apply-btn:hover{background:#eef2ff;border-color:#a5b4fc}
|
|
473
543
|
/* Dark icon buttons */
|
|
474
544
|
.tb-dk-btn{width:28px;height:28px;background:transparent;border:none;border-radius:5px;cursor:pointer;color:#71717a;display:flex;align-items:center;justify-content:center;font-size:13px;transition:all .12s;flex-shrink:0}
|
|
475
545
|
.tb-dk-btn:hover{color:#e4e4e7;background:rgba(255,255,255,.07)}
|
|
@@ -500,9 +570,29 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
500
570
|
.tb-sim-btn{background:transparent;border:1px solid #e5e7eb;border-radius:6px;color:#404040;cursor:pointer;font-size:14px;font-weight:500;padding:6px 10px;display:flex;align-items:center;gap:5px;transition:all .15s;white-space:nowrap;font-family:inherit}
|
|
501
571
|
.tb-sim-btn:hover{background:rgba(255,255,255,.06);border-color:#52525b}
|
|
502
572
|
.tb-sim-btn i{font-size:11px}
|
|
503
|
-
.tb-fin-btn{
|
|
504
|
-
|
|
505
|
-
|
|
573
|
+
.tb-fin-btn{ border: none;
|
|
574
|
+
cursor: pointer;
|
|
575
|
+
transition: all .15s;
|
|
576
|
+
white-space: nowrap;
|
|
577
|
+
border-radius: var(--radius-md, 6px);
|
|
578
|
+
background: var(--bg-primary-default, #262626);
|
|
579
|
+
padding: 7px 10px;
|
|
580
|
+
color: var(--content-on-color, #FFF);
|
|
581
|
+
text-align: center;
|
|
582
|
+
font-family: Inter;
|
|
583
|
+
font-size: var(--font-size-sm, 14px);
|
|
584
|
+
font-style: normal;
|
|
585
|
+
font-weight: 500;
|
|
586
|
+
line-height: var(--font-leading-4, 16px);
|
|
587
|
+
}
|
|
588
|
+
.tb-fin-btn:hover{opacity:0.8;}
|
|
589
|
+
.tb-fin-btn#btn-save{
|
|
590
|
+
background: var(--bg-interactive-default, #FFF);
|
|
591
|
+
box-shadow: 0 0 1px 0 var(--Black-20, rgba(0, 0, 0, 0.20)), 0 1px 2px 0 var(--Black-5, rgba(0, 0, 0, 0.05)), 0 1px 1px 0 rgba(0, 0, 0, 0.01);
|
|
592
|
+
border: none;
|
|
593
|
+
color: var(--content-success-default, #00C951);
|
|
594
|
+
font-weight: 500;
|
|
595
|
+
}
|
|
506
596
|
/* \u2500\u2500 Page loading hint (toolbar + sidebar) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
507
597
|
.tb-page-loading{
|
|
508
598
|
display:none;flex-shrink:0;align-items:center;margin:0 10px 0 4px;
|
|
@@ -559,14 +649,17 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
559
649
|
|
|
560
650
|
/* \u2500\u2500 Left panel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
561
651
|
#left-panel{
|
|
562
|
-
width:
|
|
563
|
-
display:flex;flex-direction:column;flex-shrink:0;min-height:0;overflow:hidden
|
|
652
|
+
width:288px;
|
|
653
|
+
display:flex;flex-direction:column;flex-shrink:0;min-height:0;overflow:hidden;
|
|
654
|
+
border-right: 1px solid var(--border-default, #E5E5E5);
|
|
655
|
+
background: var(--cu-Background-Main, #FFF);
|
|
564
656
|
}
|
|
565
657
|
|
|
566
658
|
/* \u2500\u2500 Iframe panel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
567
659
|
#iframe-panel{
|
|
568
660
|
flex:1;background:#e8ecf0;display:flex;flex-direction:column;
|
|
569
|
-
align-items:center;justify-content:flex-start;overflow:
|
|
661
|
+
align-items:center;justify-content:flex-start;overflow:hidden;position:relative;
|
|
662
|
+
min-height:0;min-width:0
|
|
570
663
|
}
|
|
571
664
|
|
|
572
665
|
/* \u2500\u2500 Floating selection toolbar (above iframe selection) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
@@ -587,13 +680,34 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
587
680
|
#selection-floater .sf-sep{width:1px;height:16px;background:var(--border);margin:0 2px;flex-shrink:0}
|
|
588
681
|
|
|
589
682
|
/* \u2500\u2500 DOM tree (Elements tab) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
590
|
-
.dt-tree{
|
|
683
|
+
.dt-tree{user-select:none}
|
|
591
684
|
.dt-row{
|
|
592
|
-
|
|
593
|
-
|
|
685
|
+
width: 100%;
|
|
686
|
+
display: flex;
|
|
687
|
+
align-items: center;
|
|
688
|
+
gap: 2px;
|
|
689
|
+
min-height: 26px;
|
|
690
|
+
padding: 10px 8px 10px 4px;
|
|
691
|
+
cursor: pointer;
|
|
692
|
+
color: var(--text-2);
|
|
693
|
+
position: relative;
|
|
594
694
|
}
|
|
595
695
|
.dt-row:hover{background:var(--bg-hover);color:var(--text)}
|
|
596
|
-
.dt-row.dt-selected{background
|
|
696
|
+
.dt-row.dt-selected{position:relative;background:var(--bg-hover);}
|
|
697
|
+
.dt-row.dt-selected::before, .dt-row:hover::before{
|
|
698
|
+
display: block;
|
|
699
|
+
content: '';
|
|
700
|
+
position: absolute;
|
|
701
|
+
top: 0;
|
|
702
|
+
left: 0px;
|
|
703
|
+
height: 100%;
|
|
704
|
+
width: 2px;
|
|
705
|
+
background: #262626;
|
|
706
|
+
}
|
|
707
|
+
.dt-row.dt-selected .dt-lbl .dt-tag{
|
|
708
|
+
background: var(--bg-primary-default, #262626)!important;
|
|
709
|
+
color: var(--text-primary-default, #FFF)!important;
|
|
710
|
+
}
|
|
597
711
|
.dt-chev{
|
|
598
712
|
width:16px;height:16px;flex-shrink:0;border:none;background:transparent;
|
|
599
713
|
cursor:pointer;color:var(--text-3);display:flex;align-items:center;justify-content:center;
|
|
@@ -602,22 +716,36 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
602
716
|
.dt-chev:hover{color:var(--text)}
|
|
603
717
|
.dt-chev.dt-spacer{visibility:hidden;pointer-events:none}
|
|
604
718
|
.dt-ico{width:16px;flex-shrink:0;text-align:center;color:var(--text-3);font-size:12px}
|
|
605
|
-
.dt-lbl{
|
|
719
|
+
.dt-lbl{
|
|
720
|
+
flex: 1;
|
|
721
|
+
overflow: hidden;
|
|
722
|
+
text-overflow: ellipsis;
|
|
723
|
+
white-space: nowrap;
|
|
724
|
+
color: var(--content-strong, #171717);
|
|
725
|
+
font-family: "JetBrains Mono";
|
|
726
|
+
}
|
|
606
727
|
.dt-muted{padding:16px 12px;text-align:center;color:var(--text-3);font-size:11px;line-height:1.4}
|
|
607
728
|
#section-components-panel{
|
|
608
729
|
max-height: 50%;
|
|
609
730
|
overflow-y: auto;
|
|
731
|
+
flex-shrink: 0;
|
|
732
|
+
display: flex;
|
|
733
|
+
flex-direction: column;
|
|
610
734
|
}
|
|
735
|
+
#section-components-panel .lp-body.collapsed{display:none}
|
|
611
736
|
/* \u2500\u2500 Right panel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
612
737
|
#right-panel{
|
|
613
|
-
width:
|
|
738
|
+
width:288px;
|
|
739
|
+
border-left: 1px solid var(--border-default, #E5E5E5);
|
|
740
|
+
background: var(--cu-Background-Main, #FFF);
|
|
614
741
|
display:flex;flex-direction:column;flex-shrink:0;overflow:hidden
|
|
615
742
|
}
|
|
616
743
|
|
|
617
744
|
/* \u2500\u2500 Breadcrumb \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
618
745
|
#breadcrumb{
|
|
746
|
+
display:none;
|
|
619
747
|
height:26px;background:var(--bg);border-top:1px solid var(--border);
|
|
620
|
-
|
|
748
|
+
align-items:center;padding:0 12px;font-size:11px;
|
|
621
749
|
color:var(--text-3);flex-shrink:0;gap:5px;overflow:hidden
|
|
622
750
|
}
|
|
623
751
|
|
|
@@ -630,9 +758,13 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
630
758
|
|
|
631
759
|
/* \u2500\u2500 Device frame \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
632
760
|
#device-frame{
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
761
|
+
width: 100%;
|
|
762
|
+
min-height: 100%;
|
|
763
|
+
display: flex;
|
|
764
|
+
align-items: center;
|
|
765
|
+
transform-origin: top left;
|
|
766
|
+
transition: max-width .3s ease,width .2s ease,height .2s ease;
|
|
767
|
+
flex-shrink: 0;
|
|
636
768
|
}
|
|
637
769
|
#device-frame.desktop{
|
|
638
770
|
max-width:1440px;
|
|
@@ -683,33 +815,51 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
683
815
|
}
|
|
684
816
|
|
|
685
817
|
/* \u2500\u2500 Left panel sections \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
686
|
-
.lp-sec{border-bottom:1px solid var(--border);flex-shrink:0;padding: 24px;}
|
|
818
|
+
.lp-sec{border-bottom:1px solid var(--border);flex-shrink:0;padding: 24px 16px;}
|
|
687
819
|
.lp-sec-no-border{border-bottom:none!important}
|
|
688
820
|
.lp-sec-hd{
|
|
689
821
|
margin-bottom: 12px;
|
|
690
822
|
font-size:14px;font-weight:600;
|
|
823
|
+
line-height: 20px;
|
|
691
824
|
color:#404040;display:flex;align-items:center;justify-content:space-between;gap:5px
|
|
692
825
|
}
|
|
693
826
|
.lp-sec-hd-left{display:flex;align-items:center;gap:5px}
|
|
694
827
|
#active-var-label{display:none;color:var(--accent-txt);font-size:10px;font-weight:500}
|
|
695
828
|
.lp-info-icon{font-size:11px;color:var(--text-3);cursor:default;opacity:.7}
|
|
696
829
|
.lp-add-btn{
|
|
697
|
-
|
|
698
|
-
|
|
830
|
+
background: none;
|
|
831
|
+
border: none;
|
|
832
|
+
cursor: pointer;
|
|
833
|
+
padding: 2px 5px;
|
|
834
|
+
border-radius: 4px;
|
|
835
|
+
transition: all .12s;
|
|
836
|
+
flex-shrink: 0;
|
|
837
|
+
color: var(--content-default, #404040);
|
|
838
|
+
text-align: center;
|
|
839
|
+
font-family: Inter;
|
|
840
|
+
font-size: 12px;
|
|
841
|
+
font-style: normal;
|
|
842
|
+
font-weight: 500;
|
|
843
|
+
line-height: 14px;
|
|
699
844
|
}
|
|
700
|
-
.lp-add-btn:hover{
|
|
845
|
+
.lp-add-btn:hover{opacity:0.8}
|
|
701
846
|
|
|
702
847
|
/* \u2500\u2500 Variation tabs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
703
848
|
#variation-tabs{display:flex;flex-direction:column; gap:8px;}
|
|
704
849
|
.var-tab{
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
850
|
+
border-radius: var(--radius-md, 6px);
|
|
851
|
+
border:1px solid transparent;
|
|
852
|
+
background: var(--bg-interactive-default, #FFF);
|
|
853
|
+
box-shadow: 0 0 1px 0 var(--Black-20, rgba(0, 0, 0, 0.20)), 0 1px 2px 0 var(--Black-5, rgba(0, 0, 0, 0.05)), 0 1px 1px 0 rgba(0, 0, 0, 0.01);
|
|
854
|
+
cursor:pointer;font-size:15px;font-weight:500;padding:7px 10px;transition:background .12s,color .12s,border-color .12s;
|
|
709
855
|
width:100%;text-align:left;display:flex;align-items:center;gap:8px;
|
|
856
|
+
line-height: 16px;
|
|
710
857
|
}
|
|
711
858
|
.var-tab:hover{background:var(--bg-hover);color:var(--text)}
|
|
712
|
-
.var-tab.active{
|
|
859
|
+
button.var-tab.active{
|
|
860
|
+
color:var(--accent-txt);
|
|
861
|
+
border-color:var(--var-tab-color, transparent);
|
|
862
|
+
}
|
|
713
863
|
.var-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}
|
|
714
864
|
.var-add-row{
|
|
715
865
|
display:none!important;
|
|
@@ -723,51 +873,207 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
723
873
|
.var-add-row:hover{color:var(--accent-txt)}
|
|
724
874
|
|
|
725
875
|
/* \u2500\u2500 Search \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
876
|
+
.lp-search-container{margin-bottom:8px}
|
|
877
|
+
.lp-search-field{
|
|
878
|
+
position:relative;
|
|
879
|
+
display:flex;
|
|
880
|
+
align-items:center;
|
|
881
|
+
width:100%;
|
|
882
|
+
}
|
|
883
|
+
.lp-search-icon{
|
|
884
|
+
position:absolute;
|
|
885
|
+
left:12px;
|
|
886
|
+
top:50%;
|
|
887
|
+
transform:translateY(-50%);
|
|
888
|
+
display:flex;
|
|
889
|
+
align-items:center;
|
|
890
|
+
justify-content:center;
|
|
891
|
+
width:16px;
|
|
892
|
+
height:16px;
|
|
893
|
+
pointer-events:none;
|
|
894
|
+
color:var(--base-sub-2,#B5B5B5);
|
|
895
|
+
flex-shrink:0;
|
|
896
|
+
}
|
|
897
|
+
.lp-search-icon svg{display:block;width:16px;height:16px}
|
|
898
|
+
.lp-search-icon svg path{stroke:currentColor}
|
|
726
899
|
#comp-search{
|
|
727
|
-
|
|
728
|
-
color:var(--text);
|
|
900
|
+
border:1px solid var(--border);
|
|
901
|
+
color:var(--text);
|
|
902
|
+
font-size:12px;
|
|
903
|
+
padding:9px 12px 9px 36px;
|
|
904
|
+
width:100%;
|
|
905
|
+
outline:none;
|
|
906
|
+
border-radius:6px;
|
|
907
|
+
background:var(--Greyscale-0,#FFF);
|
|
908
|
+
box-shadow:0 0 1px 0 var(--Black-20,rgba(0,0,0,.20)),0 1px 2px 0 var(--Black-5,rgba(0,0,0,.05)),0 1px 1px 0 rgba(0,0,0,.01);
|
|
729
909
|
}
|
|
730
|
-
#comp-search::placeholder{
|
|
731
|
-
|
|
732
|
-
|
|
910
|
+
#comp-search::placeholder{
|
|
911
|
+
color:var(--base-sub-2,#B5B5B5);
|
|
912
|
+
font-size:var(--font-size-sm,14px);
|
|
913
|
+
font-style:normal;
|
|
914
|
+
font-weight:500;
|
|
915
|
+
}
|
|
916
|
+
#comp-search:focus{border-color:#000;}
|
|
733
917
|
/* \u2500\u2500 Left tabs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
734
|
-
.lp-tabs
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
918
|
+
.lp-tabs-container{
|
|
919
|
+
display:flex;
|
|
920
|
+
align-items:center;
|
|
921
|
+
justify-content:space-between;
|
|
738
922
|
}
|
|
739
|
-
.lp-
|
|
740
|
-
|
|
741
|
-
|
|
923
|
+
.lp-tabs{
|
|
924
|
+
width: 100%;
|
|
925
|
+
padding: 4px 10px;
|
|
926
|
+
flex: 1;
|
|
742
927
|
display: flex;
|
|
743
|
-
|
|
928
|
+
border-radius: 6px;
|
|
929
|
+
background: var(--base-soft-2,#F0F0F0);
|
|
930
|
+
padding: 4px 6px;
|
|
931
|
+
flex-shrink: 0;
|
|
932
|
+
gap: 6px;
|
|
933
|
+
align-items: center;
|
|
934
|
+
white-space: nowrap;
|
|
935
|
+
}
|
|
936
|
+
.lp-tab{
|
|
937
|
+
flex: 1;
|
|
938
|
+
text-align: center;
|
|
939
|
+
color: #404040;
|
|
940
|
+
white-space: nowrap;
|
|
941
|
+
cursor: pointer;
|
|
942
|
+
transition: all .15s;
|
|
943
|
+
line-height: 1.15;
|
|
944
|
+
font-size: var(--font-size-sm,14px);
|
|
945
|
+
font-weight: 500;
|
|
946
|
+
padding:4px 10px;
|
|
947
|
+
}
|
|
948
|
+
.section-components-tabs-container{
|
|
949
|
+
display: flex;
|
|
744
950
|
align-items: center;
|
|
745
|
-
justify-content:
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
951
|
+
justify-content: space-between;
|
|
952
|
+
flex-shrink: 0;
|
|
953
|
+
padding: 12px 16px;
|
|
954
|
+
border-bottom: 1px solid #F5F5F5;
|
|
955
|
+
}
|
|
956
|
+
.section-components-tabs-container .lp-tabs{
|
|
957
|
+
flex:1;
|
|
749
958
|
}
|
|
959
|
+
.lp-tab.close-section-components-panel{
|
|
960
|
+
flex:0 0 auto;
|
|
961
|
+
flex-shrink:0;
|
|
962
|
+
display:flex;
|
|
963
|
+
align-items:center;
|
|
964
|
+
justify-content:center;
|
|
965
|
+
width:24px;
|
|
966
|
+
height:24px;
|
|
967
|
+
padding:0;
|
|
968
|
+
background:none;
|
|
969
|
+
border-radius:4px;
|
|
970
|
+
color:var(--content-default,#404040);
|
|
971
|
+
line-height:1;
|
|
972
|
+
white-space:nowrap;
|
|
973
|
+
}
|
|
974
|
+
.lp-tab.close-section-components-panel i{
|
|
975
|
+
font-size:14px;
|
|
976
|
+
line-height:1;
|
|
977
|
+
transition:transform .15s;
|
|
978
|
+
}
|
|
979
|
+
.lp-tab.close-section-components-panel.collapsed i{transform:rotate(-180deg)}
|
|
750
980
|
.lp-tab:hover{color:var(--text-2)}
|
|
751
|
-
.lp-tab.active{
|
|
981
|
+
.lp-tab.active{
|
|
982
|
+
border-radius:4px;
|
|
983
|
+
background:var(--bg-interactive-default,#FFF);
|
|
984
|
+
box-shadow:0 0 1px 0 var(--Black-20,rgba(0,0,0,.20)),0 1px 2px 0 var(--Black-5,rgba(0,0,0,.05)),0 1px 1px 0 rgba(0,0,0,.01);
|
|
985
|
+
}
|
|
986
|
+
.lp-tab.close-section-components-panel:hover{opacity:.8;color:var(--text-2)}
|
|
987
|
+
.lp-tab.close-section-components-panel.active{
|
|
988
|
+
background:none;
|
|
989
|
+
box-shadow:none;
|
|
990
|
+
border-radius:4px;
|
|
991
|
+
}
|
|
752
992
|
.future-hidden{display:none!important}
|
|
753
993
|
|
|
754
994
|
/* \u2500\u2500 Left panel body \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
995
|
+
.lp-body #tab-dom-tree, .lp-body #tab-elements{
|
|
996
|
+
padding-top:4px;
|
|
997
|
+
}
|
|
998
|
+
.lp-body #tab-elements .dt-lbl{
|
|
999
|
+
font-size: 12px;
|
|
1000
|
+
font-style: normal;
|
|
1001
|
+
font-weight: 500;
|
|
1002
|
+
line-height: 14px;
|
|
1003
|
+
letter-spacing: -0.1px;
|
|
1004
|
+
}
|
|
1005
|
+
.lp-body #tab-elements #elements-root > .dt-row{
|
|
1006
|
+
padding-left: 16px!important;
|
|
1007
|
+
}
|
|
1008
|
+
.lp-body #dom-tree-root .dt-lbl{
|
|
1009
|
+
color: var(--content-subtle, #737373);
|
|
1010
|
+
font-style: normal;
|
|
1011
|
+
font-weight: 400;
|
|
1012
|
+
line-height: var(--font-leading-3, 12px); /* 100% */
|
|
1013
|
+
letter-spacing: -0.1px;
|
|
1014
|
+
}
|
|
1015
|
+
.lp-body #dom-tree-root .dt-lbl .dt-tag{
|
|
1016
|
+
color: var(--content-strong, #171717);
|
|
1017
|
+
font-family: "JetBrains Mono";
|
|
1018
|
+
font-size: 12px;
|
|
1019
|
+
font-style: normal;
|
|
1020
|
+
font-weight: 500;
|
|
1021
|
+
line-height: 14px;
|
|
1022
|
+
letter-spacing: -0.1px;
|
|
1023
|
+
border-radius: 4px;
|
|
1024
|
+
background: var(--bg-surface-subtle, #F5F5F5);
|
|
1025
|
+
padding:3px 6px;
|
|
1026
|
+
display:inline-block;
|
|
1027
|
+
margin-right:4px;
|
|
1028
|
+
}
|
|
1029
|
+
.lp-body #tab-elements .dt-row .dt-chev.dt-spacer{display:none;}
|
|
1030
|
+
.lp-body #tab-dom-tree .dt-row .dt-ico{display:none;}
|
|
755
1031
|
.lp-body, .section-components-body{flex:1;overflow-y:auto}
|
|
756
1032
|
.lp-body::-webkit-scrollbar, .section-components-body::-webkit-scrollbar{width:3px}
|
|
757
1033
|
.lp-body::-webkit-scrollbar-thumb, .section-components-body::-webkit-scrollbar-thumb{background:#cbd5e1;border-radius:2px}
|
|
758
1034
|
.tab-pane, .section-components-tab-pane{display:none}.tab-pane.active, .section-components-tab-pane.active{display:block}
|
|
759
1035
|
|
|
760
1036
|
/* \u2500\u2500 Component grid \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
761
|
-
.cg-hdr{padding:
|
|
762
|
-
|
|
1037
|
+
.cg-hdr{ padding: 12px 12px;
|
|
1038
|
+
text-transform: uppercase;
|
|
1039
|
+
letter-spacing: .06em;
|
|
1040
|
+
color: var(--content-subtle, #737373);
|
|
1041
|
+
font-family: Inter;
|
|
1042
|
+
font-size: 12px;
|
|
1043
|
+
font-weight: 600;
|
|
1044
|
+
line-height: normal;
|
|
1045
|
+
}
|
|
1046
|
+
.cg-grid{ display: grid;
|
|
1047
|
+
grid-template-columns: 1fr 1fr 1fr;
|
|
1048
|
+
padding: 0 12px 12px;
|
|
1049
|
+
column-gap: 8px;
|
|
1050
|
+
row-gap: 12px;}
|
|
763
1051
|
.cg-item{
|
|
764
|
-
|
|
765
|
-
|
|
1052
|
+
background: #fff;
|
|
1053
|
+
cursor: pointer;
|
|
1054
|
+
padding: 15px 11px;
|
|
1055
|
+
text-align: center;
|
|
1056
|
+
transition: all .15s;
|
|
1057
|
+
color: var(--text-2);
|
|
1058
|
+
user-select: none;
|
|
1059
|
+
border-radius: 6px;
|
|
1060
|
+
border: 1px solid var(--border-default, #E5E5E5);
|
|
766
1061
|
}
|
|
767
1062
|
.cg-item:hover{background:var(--accent-bg);border-color:var(--accent);color:var(--accent-txt);transform:translateY(-1px);box-shadow:0 2px 8px rgba(99,102,241,.15)}
|
|
768
1063
|
.cg-item:active{transform:translateY(0);box-shadow:none}
|
|
769
|
-
.cg-icon{
|
|
770
|
-
|
|
1064
|
+
.cg-icon{ margin-bottom: 6px;
|
|
1065
|
+
color: var(--content-default, #404040);
|
|
1066
|
+
font-family: Inter;
|
|
1067
|
+
font-size: var(--font-size-sm, 14px);
|
|
1068
|
+
font-style: normal;
|
|
1069
|
+
font-weight: 500;
|
|
1070
|
+
line-height: var(--font-leading-4, 16px);}
|
|
1071
|
+
.cg-name{ color: var(--content-subtle, #737373);
|
|
1072
|
+
font-family: Inter;
|
|
1073
|
+
font-size: var(--font-size-xs, 12px);
|
|
1074
|
+
font-style: normal;
|
|
1075
|
+
font-weight: 400;
|
|
1076
|
+
line-height: var(--font-leading-3, 12px);}
|
|
771
1077
|
|
|
772
1078
|
/* \u2500\u2500 Section list \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
773
1079
|
.sec-item{
|
|
@@ -776,8 +1082,12 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
776
1082
|
}
|
|
777
1083
|
.sec-item:hover{border-color:var(--accent);transform:translateY(-1px);box-shadow:0 4px 12px rgba(99,102,241,.12)}
|
|
778
1084
|
.sec-thumb{
|
|
779
|
-
background:var(--bg-sub);height:
|
|
780
|
-
justify-content:center;font-size:22px;border-bottom:1px solid var(--border)
|
|
1085
|
+
background:var(--bg-sub);height:72px;display:flex;align-items:center;
|
|
1086
|
+
justify-content:center;font-size:22px;border-bottom:1px solid var(--border);
|
|
1087
|
+
overflow:hidden;
|
|
1088
|
+
}
|
|
1089
|
+
.sec-thumb img{
|
|
1090
|
+
width:100%;height:100%;object-fit:cover;object-position:top center;display:block;
|
|
781
1091
|
}
|
|
782
1092
|
.sec-info{padding:7px 9px}
|
|
783
1093
|
.sec-name{font-size:11px;font-weight:600;color:var(--text)}
|
|
@@ -793,9 +1103,9 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
793
1103
|
#no-sel .ns-icon{font-size:32px;margin-bottom:10px;opacity:.4}
|
|
794
1104
|
|
|
795
1105
|
/* \u2500\u2500 Element info header \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
796
|
-
#el-info{padding:8px 12px;border-bottom:1px solid var(--border);background:var(--bg-sub);flex-shrink:0}
|
|
797
|
-
#el-info-tag{font-size:10px;font-weight:700;color:var(--text-3);text-transform:uppercase;letter-spacing:.05em;font-family:
|
|
798
|
-
#el-info-sel{font-size:10px;color:var(--accent-txt);font-family:
|
|
1106
|
+
#el-info{padding:8px 12px;border-bottom:1px solid var(--border);background:var(--bg-sub);flex-shrink:0;display:none;}
|
|
1107
|
+
#el-info-tag{font-size:10px;font-weight:700;color:var(--text-3);text-transform:uppercase;letter-spacing:.05em;font-family:var(--font-mono)}
|
|
1108
|
+
#el-info-sel{font-size:10px;color:var(--accent-txt);font-family:var(--font-mono);margin-top:2px;word-break:break-all;opacity:.8}
|
|
799
1109
|
|
|
800
1110
|
/* \u2500\u2500 Accordion \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
801
1111
|
.acc-section{border-bottom:1px solid var(--border-sub)}
|
|
@@ -850,7 +1160,7 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
850
1160
|
.custom-css-close:hover{background:var(--bg-hover);color:var(--text)}
|
|
851
1161
|
#custom-css-modal-textarea{
|
|
852
1162
|
width:100%;min-height:360px;max-height:58vh;resize:vertical;border:none;outline:none;
|
|
853
|
-
font-family:
|
|
1163
|
+
font-family:var(--font-mono);
|
|
854
1164
|
font-size:12px;line-height:1.5;padding:12px;background:#0b1220;color:#e2e8f0
|
|
855
1165
|
}
|
|
856
1166
|
.custom-css-actions{
|
|
@@ -893,7 +1203,7 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
893
1203
|
.adv-section{padding:10px}
|
|
894
1204
|
.adv-row{margin-bottom:8px}
|
|
895
1205
|
.adv-key{font-size:10px;color:var(--text-3);margin-bottom:3px;font-weight:700;text-transform:uppercase;letter-spacing:.05em}
|
|
896
|
-
.adv-val{font-size:11px;color:var(--text-2);word-break:break-all;background:var(--bg-sub);padding:5px 7px;border-radius:5px;font-family:
|
|
1206
|
+
.adv-val{font-size:11px;color:var(--text-2);word-break:break-all;background:var(--bg-sub);padding:5px 7px;border-radius:5px;font-family:var(--font-mono);border:1px solid var(--border)}
|
|
897
1207
|
|
|
898
1208
|
/* \u2500\u2500 Selected element ring + drag affordance \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
899
1209
|
/* Selection chrome is injected into the iframe (see injectIframeSelectionStyles); rules here are fallback only */
|
|
@@ -927,14 +1237,37 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
927
1237
|
.img-add:hover{border-color:var(--accent);color:var(--accent-txt);background:var(--accent-bg)}
|
|
928
1238
|
|
|
929
1239
|
/* \u2500\u2500 Right panel main tabs (Design / States / History) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
930
|
-
#main-tabs{
|
|
1240
|
+
#main-tabs{
|
|
1241
|
+
display:flex;
|
|
1242
|
+
align-items:center;
|
|
1243
|
+
gap:6px;
|
|
1244
|
+
margin:12px 16px 8px;
|
|
1245
|
+
padding:4px 6px;
|
|
1246
|
+
border-radius:6px;
|
|
1247
|
+
background:var(--base-soft-2,#F0F0F0);
|
|
1248
|
+
flex-shrink:0;
|
|
1249
|
+
}
|
|
931
1250
|
.main-tab{
|
|
932
|
-
flex:1;
|
|
933
|
-
|
|
934
|
-
|
|
1251
|
+
flex:1;
|
|
1252
|
+
padding:4px 10px;
|
|
1253
|
+
text-align:center;
|
|
1254
|
+
font-size:var(--font-size-sm,14px);
|
|
1255
|
+
font-weight:500;
|
|
1256
|
+
line-height:1.15;
|
|
1257
|
+
color:#404040;
|
|
1258
|
+
white-space:nowrap;
|
|
1259
|
+
cursor:pointer;
|
|
1260
|
+
border:none;
|
|
1261
|
+
background:transparent;
|
|
1262
|
+
transition:all .15s;
|
|
1263
|
+
font-family:inherit;
|
|
935
1264
|
}
|
|
936
1265
|
.main-tab:hover{color:var(--text-2)}
|
|
937
|
-
.main-tab.active{
|
|
1266
|
+
.main-tab.active{
|
|
1267
|
+
border-radius:4px;
|
|
1268
|
+
background:var(--bg-interactive-default,#FFF);
|
|
1269
|
+
box-shadow:0 0 1px 0 var(--Black-20,rgba(0,0,0,.20)),0 1px 2px 0 var(--Black-5,rgba(0,0,0,.05)),0 1px 1px 0 rgba(0,0,0,.01);
|
|
1270
|
+
}
|
|
938
1271
|
.rp-pane{flex:1;overflow-y:auto;overflow-x:hidden;min-width:0;display:none}
|
|
939
1272
|
.rp-pane.active{display:block}
|
|
940
1273
|
|
|
@@ -943,13 +1276,13 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
943
1276
|
.states-empty i{font-size:30px;display:block;margin-bottom:10px;opacity:.3}
|
|
944
1277
|
.state-group{border-bottom:1px solid var(--border-sub)}
|
|
945
1278
|
.state-group-sel{
|
|
946
|
-
padding:8px 12px 3px;font-size:10px;font-family:
|
|
1279
|
+
padding:8px 12px 3px;font-size:10px;font-family:var(--font-mono);
|
|
947
1280
|
color:var(--text-3);font-weight:700;word-break:break-all;letter-spacing:-.01em
|
|
948
1281
|
}
|
|
949
1282
|
.state-item{display:flex;align-items:center;padding:4px 10px 4px 18px;gap:6px}
|
|
950
1283
|
.state-item-label{flex:1;font-size:11px;color:var(--text-2)}
|
|
951
1284
|
.state-item-val{
|
|
952
|
-
font-size:10px;color:var(--accent-txt);font-family:
|
|
1285
|
+
font-size:10px;color:var(--accent-txt);font-family:var(--font-mono);
|
|
953
1286
|
max-width:68px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
|
|
954
1287
|
background:var(--accent-bg);padding:1px 5px;border-radius:3px
|
|
955
1288
|
}
|
|
@@ -1077,7 +1410,17 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1077
1410
|
<div id="dev-more-menu" class="tb-dev-menu" aria-hidden="true">
|
|
1078
1411
|
<div class="row row-zoom">
|
|
1079
1412
|
<label for="dev-zoom-level">Zoom</label>
|
|
1080
|
-
<
|
|
1413
|
+
<div class="zoom-controls">
|
|
1414
|
+
<button type="button" id="dev-zoom-fit-btn" class="dev-zoom-fit-btn" title="Reset zoom to fit window" aria-label="Reset zoom to fit window">
|
|
1415
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true">
|
|
1416
|
+
<path d="M2.66699 5.33333V2.66667C2.66699 2.48986 2.73723 2.32029 2.86225 2.19526C2.98727 2.07024 3.15684 2 3.33366 2H6.00033" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
|
1417
|
+
<path d="M10 2H12.6667C12.8435 2 13.013 2.07024 13.1381 2.19526C13.2631 2.32029 13.3333 2.48986 13.3333 2.66667V5.33333" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
|
1418
|
+
<path d="M13.333 10.6667V13.3333C13.333 13.5101 13.2628 13.6797 13.1377 13.8047C13.0127 13.9298 12.8432 14 12.6663 14H10" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
|
1419
|
+
<path d="M6 14H3.33333C3.15652 14 2.98695 13.9298 2.86193 13.8047C2.73691 13.6797 2.66667 13.5101 2.66667 13.3333V10.6667" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
|
1420
|
+
</svg>
|
|
1421
|
+
</button>
|
|
1422
|
+
<input id="dev-zoom-level" type="number" min="25" max="200" step="5" value="100" />
|
|
1423
|
+
</div>
|
|
1081
1424
|
</div>
|
|
1082
1425
|
<div class="row row-split row-width height-width-row">
|
|
1083
1426
|
<div class="row" style="margin:0">
|
|
@@ -1102,9 +1445,6 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1102
1445
|
<button type="button" class="vp-preset-btn" data-preset="iphone-7">iPhone 7</button>
|
|
1103
1446
|
<button type="button" class="vp-preset-btn" data-preset="responsive">Responsive</button>
|
|
1104
1447
|
</div>
|
|
1105
|
-
<div class="ft">
|
|
1106
|
-
<button type="button" class="apply-btn" id="dev-apply-btn">Apply</button>
|
|
1107
|
-
</div>
|
|
1108
1448
|
</div>
|
|
1109
1449
|
</div>
|
|
1110
1450
|
<button class="tb-dk-btn" id="btn-undo" title="Undo (\u2318Z)"><i class="bi bi-arrow-counterclockwise"></i></button>
|
|
@@ -1132,15 +1472,16 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1132
1472
|
<span class="tb-save-txt"></span>
|
|
1133
1473
|
<span id="tb-save-time" class="tb-save-time"></span>
|
|
1134
1474
|
</div>
|
|
1475
|
+
<button class="tb-fin-btn" id="btn-save">Save Changes</button>
|
|
1135
1476
|
<div class="tb-dev-3btns">
|
|
1136
1477
|
<button class="tb-dk-btn active" id="btn-mode-editor" onclick="setMode('editor')" title="Edit mode \u2014 click elements to edit"><i class="bi bi-pencil"></i></button>
|
|
1137
|
-
<button class="tb-dk-btn" id="btn-mode-nav" onclick="setMode('navigate')" title="Navigate mode \u2014 interact with page normally"><i class="bi bi-
|
|
1478
|
+
<button class="tb-dk-btn" id="btn-mode-nav" onclick="setMode('navigate')" title="Navigate mode \u2014 interact with page normally"><i class="bi bi-cursor"></i></button>
|
|
1138
1479
|
<button class="tb-dk-btn" title="Comments"><i class="bi bi-chat-dots"></i></button>
|
|
1139
1480
|
</div>
|
|
1140
|
-
<button class="tb-sim-btn" id="btn-simulate" onclick="simulateExperiment()"
|
|
1141
|
-
|
|
1481
|
+
<button class="tb-sim-btn" id="btn-simulate" onclick="simulateExperiment()">See Preview</button>
|
|
1482
|
+
|
|
1142
1483
|
<!-- btn-close: kept for JS event listener -->
|
|
1143
|
-
<button class="tb-fin-btn" id="btn-close">
|
|
1484
|
+
<button class="tb-fin-btn" id="btn-close">Exit Editor</button>
|
|
1144
1485
|
</div>
|
|
1145
1486
|
|
|
1146
1487
|
<!-- url-bar: hidden, kept for JS compatibility -->
|
|
@@ -1178,22 +1519,28 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1178
1519
|
|
|
1179
1520
|
<!-- Elements -->
|
|
1180
1521
|
<div class="lp-sec lp-sec-no-border">
|
|
1181
|
-
<div class="lp-sec-hd">
|
|
1182
|
-
<span class="lp-sec-hd-left">Elements <i style="display:none" class="bi bi-info-circle lp-info-icon" title="Page elements"></i></span>
|
|
1183
|
-
<button class="lp-add-btn" id="btn-add-element" title="Add element">+ Add</button>
|
|
1184
|
-
</div>
|
|
1185
|
-
|
|
1186
1522
|
<!-- Search (hidden, kept for JS) -->
|
|
1187
|
-
<div>
|
|
1188
|
-
<
|
|
1523
|
+
<div class="lp-search-container">
|
|
1524
|
+
<div class="lp-search-field">
|
|
1525
|
+
<span class="lp-search-icon" aria-hidden="true">
|
|
1526
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
|
|
1527
|
+
<path d="M11.333 11.3333L13.9997 13.9999" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
|
1528
|
+
<path d="M12.6667 7.33333C12.6667 4.38781 10.2789 2 7.33333 2C4.38781 2 2 4.38781 2 7.33333C2 10.2789 4.38781 12.6667 7.33333 12.6667C10.2789 12.6667 12.6667 10.2789 12.6667 7.33333Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
|
1529
|
+
</svg>
|
|
1530
|
+
</span>
|
|
1531
|
+
<input type="search" id="comp-search" placeholder="Search" autocomplete="off">
|
|
1532
|
+
</div>
|
|
1189
1533
|
</div>
|
|
1190
1534
|
|
|
1191
1535
|
|
|
1192
1536
|
<!-- Tabs (hidden, kept for JS) -->
|
|
1193
|
-
<div class="lp-tabs"
|
|
1194
|
-
<div class="lp-
|
|
1537
|
+
<div class="lp-tabs-container">
|
|
1538
|
+
<div class="lp-tabs">
|
|
1539
|
+
<div class="lp-tab active" onclick="switchLeftTab('elements')">Elements</div>
|
|
1195
1540
|
<div class="lp-tab" onclick="switchLeftTab('dom-tree')">DOM Tree</div>
|
|
1196
1541
|
</div>
|
|
1542
|
+
<button class="lp-add-btn" id="btn-add-element" title="Add element">+ Add</button>
|
|
1543
|
+
</div>
|
|
1197
1544
|
|
|
1198
1545
|
</div>
|
|
1199
1546
|
|
|
@@ -1222,11 +1569,11 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1222
1569
|
|
|
1223
1570
|
<!-- Floating toolbar for selected element (positioned over iframe) -->
|
|
1224
1571
|
<div id="selection-floater" aria-label="Selection actions">
|
|
1572
|
+
<button type="button" class="sf-btn" id="sf-add" title="Add element"><i class="bi bi-plus-lg"></i></button>
|
|
1573
|
+
<span class="sf-sep"></span>
|
|
1225
1574
|
<button type="button" class="sf-btn" id="sf-move-up" title="Move up"><i class="bi bi-arrow-up"></i></button>
|
|
1226
1575
|
<button type="button" class="sf-btn" id="sf-move-down" title="Move down"><i class="bi bi-arrow-down"></i></button>
|
|
1227
1576
|
<span class="sf-sep"></span>
|
|
1228
|
-
<button type="button" class="sf-btn" id="sf-resize" disabled title="Resize (coming soon)"><i class="bi bi-arrows-angle-expand"></i></button>
|
|
1229
|
-
<button type="button" class="sf-btn" id="sf-rotate" disabled title="Rotate (coming soon)"><i class="bi bi-arrow-repeat"></i></button>
|
|
1230
1577
|
<button type="button" class="sf-btn" id="sf-dup" title="Duplicate"><i class="bi bi-files"></i></button>
|
|
1231
1578
|
<button type="button" class="sf-btn" id="sf-hide" title="Hide"><i class="bi bi-eye-slash"></i></button>
|
|
1232
1579
|
<button type="button" class="sf-btn" id="sf-del" title="Delete"><i class="bi bi-trash"></i></button>
|
|
@@ -1250,14 +1597,16 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1250
1597
|
|
|
1251
1598
|
<!-- Right panel -->
|
|
1252
1599
|
<div id="right-panel">
|
|
1253
|
-
<div id="section-components-panel"
|
|
1600
|
+
<div id="section-components-panel">
|
|
1254
1601
|
<!-- Left-tab controls moved here -->
|
|
1255
|
-
<div class="section-components-tabs">
|
|
1256
|
-
<div class="lp-
|
|
1257
|
-
|
|
1258
|
-
|
|
1602
|
+
<div class="lp-tabs-container section-components-tabs-container">
|
|
1603
|
+
<div class="lp-tabs">
|
|
1604
|
+
<div class="lp-tab" onclick="switchSectionComponentsTab('components')">Components</div>
|
|
1605
|
+
<div class="lp-tab" onclick="switchSectionComponentsTab('sections')">Sections</div>
|
|
1606
|
+
</div>
|
|
1607
|
+
<div class="lp-tab close-section-components-panel collapsed" onclick="toggleSectionComponentsBody()" title="Toggle components list"><i class="bi bi-chevron-down"></i></div>
|
|
1259
1608
|
</div>
|
|
1260
|
-
<div class="lp-body">
|
|
1609
|
+
<div class="lp-body collapsed">
|
|
1261
1610
|
<div id="tab-components" class="tab-pane"></div>
|
|
1262
1611
|
<div id="tab-sections" class="tab-pane"></div>
|
|
1263
1612
|
</div>
|
|
@@ -1270,7 +1619,7 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1270
1619
|
<!-- \u2500\u2500 3 main tabs \u2500\u2500 -->
|
|
1271
1620
|
<div id="main-tabs">
|
|
1272
1621
|
<button class="main-tab active" onclick="switchMainTab('design')">Design</button>
|
|
1273
|
-
<button class="main-tab" onclick="switchMainTab('states')">States</button>
|
|
1622
|
+
<button class="main-tab" style="display:none" onclick="switchMainTab('states')">States</button>
|
|
1274
1623
|
<button class="main-tab" onclick="switchMainTab('history')">History</button>
|
|
1275
1624
|
</div>
|
|
1276
1625
|
|
|
@@ -1460,26 +1809,35 @@ if (window.Vvveb && window.Vvveb.Components) {
|
|
|
1460
1809
|
|
|
1461
1810
|
// \u2500\u2500 CRO definitions + Base components \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
1462
1811
|
var CRO_SECTIONS = ${sectionsJson};
|
|
1812
|
+
var CRO_SECTION_IMAGE_ROUTE = ${JSON.stringify(CRO_SECTION_IMAGE_ROUTE)};
|
|
1813
|
+
|
|
1814
|
+
function renderCroSectionThumb(sec) {
|
|
1815
|
+
if (sec && sec.image) {
|
|
1816
|
+
return '<img src="' + CRO_SECTION_IMAGE_ROUTE + sec.image + '" alt="' + esc(sec.name || '') + '" loading="lazy">';
|
|
1817
|
+
}
|
|
1818
|
+
return sec && sec.icon ? sec.icon : '\u{1F4E6}';
|
|
1819
|
+
}
|
|
1463
1820
|
|
|
1464
1821
|
var BASE_COMPONENTS = [
|
|
1465
|
-
{ name:'Heading', icon:'bi-type-h1', html:'<h2>Your Heading</h2>' },
|
|
1466
|
-
{ name:'Paragraph', icon:'bi-paragraph', html:'<p>Your text here. Click to edit.</p>' },
|
|
1467
|
-
{ name:'Image', icon:'bi-image', html:'<img src="https://placehold.co/600x300/1a1a2e/a78bfa?text=Image" alt="Image" style="max-width:100
|
|
1468
|
-
{ name:'Button', icon:'bi-hand-index', html:'<button
|
|
1469
|
-
{ name:'Link', icon:'bi-link-45deg', html:'<a href="#">Link text</a>' },
|
|
1470
|
-
{ name:'Divider', icon:'bi-dash-lg', html:'<hr>' },
|
|
1471
|
-
{ name:'List', icon:'bi-list-ul', html:'<ul><li>Item 1</li><li>Item 2</li><li>Item 3</li></ul>' },
|
|
1472
|
-
{ name:'Video', icon:'bi-play-circle', html:'<video controls style="max-width:100
|
|
1473
|
-
{ name:'
|
|
1474
|
-
{ name:'
|
|
1475
|
-
{ name:'
|
|
1476
|
-
{ name:'
|
|
1477
|
-
{ name:'
|
|
1478
|
-
{ name:'
|
|
1479
|
-
{ name:'
|
|
1480
|
-
{ name:'
|
|
1481
|
-
{ name:'
|
|
1482
|
-
{ name:'
|
|
1822
|
+
{ name:'Heading', icon:'bi-type-h1', defaultAccSection:'typography', html:'<h2 style="margin:0 0 12px;font-size:28px;font-weight:700;line-height:1.2;color:#0f172a">Your Heading</h2>' },
|
|
1823
|
+
{ name:'Paragraph', icon:'bi-paragraph', defaultAccSection:'typography', html:'<p style="margin:0 0 12px;font-size:16px;line-height:1.6;color:#334155">Your text here. Click to edit.</p>' },
|
|
1824
|
+
{ name:'Image', icon:'bi-image', defaultAccSection:'image', html:'<img src="https://placehold.co/600x300/1a1a2e/a78bfa?text=Image" alt="Image" style="display:block;max-width:100%;height:auto;border-radius:8px">' },
|
|
1825
|
+
{ name:'Button', icon:'bi-hand-index', defaultAccSection:'background', html:'<button type="button" style="display:inline-block;padding:10px 20px;font-size:14px;font-weight:600;line-height:1.2;color:#fff;background:#2563eb;border:none;border-radius:6px;cursor:pointer">Click me</button>' },
|
|
1826
|
+
{ name:'Link', icon:'bi-link-45deg', defaultAccSection:'typography', html:'<a href="#" style="font-size:16px;font-weight:500;color:#2563eb;text-decoration:underline">Link text</a>' },
|
|
1827
|
+
{ name:'Divider', icon:'bi-dash-lg', defaultAccSection:'background', html:'<hr style="margin:16px 0;border:none;border-top:1px solid #e2e8f0">' },
|
|
1828
|
+
{ name:'List', icon:'bi-list-ul', defaultAccSection:'typography', html:'<ul style="margin:0 0 12px;padding-left:20px;font-size:16px;line-height:1.6;color:#334155"><li>Item 1</li><li>Item 2</li><li>Item 3</li></ul>' },
|
|
1829
|
+
{ name:'Video', icon:'bi-play-circle', defaultAccSection:'content', html:'<video controls style="display:block;width:100%;max-width:100%;border-radius:8px;background:#000"><source src="" type="video/mp4"></video>' },
|
|
1830
|
+
{ name:'Youtube Video', icon:'bi-youtube', defaultAccSection:'content', html:'<iframe data-youtube-id="" src="about:blank" title="YouTube video" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen style="display:block;width:100%;max-width:100%;aspect-ratio:16/9;border:none;border-radius:8px;background:#000"></iframe>' },
|
|
1831
|
+
{ name:'Vimeo Video', icon:'bi-vimeo', defaultAccSection:'content', html:'<iframe data-vimeo-id="" src="about:blank" title="Vimeo video" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen style="display:block;width:100%;max-width:100%;aspect-ratio:16/9;border:none;border-radius:8px;background:#000"></iframe>' },
|
|
1832
|
+
{ name:'Form', icon:'bi-ui-radios', defaultAccSection:'content', html:'<form style="padding:16px;border:1px solid #e2e8f0;border-radius:8px;background:#fff;max-width:400px;box-sizing:border-box"><div style="margin-bottom:12px"><label style="display:block;margin-bottom:4px;font-size:14px;font-weight:500;color:#334155">Name</label><input type="text" style="width:100%;padding:8px 12px;font-size:14px;border:1px solid #cbd5e1;border-radius:6px;box-sizing:border-box"></div><div style="margin-bottom:12px"><label style="display:block;margin-bottom:4px;font-size:14px;font-weight:500;color:#334155">Email</label><input type="email" style="width:100%;padding:8px 12px;font-size:14px;border:1px solid #cbd5e1;border-radius:6px;box-sizing:border-box"></div><button type="submit" style="display:inline-block;padding:10px 20px;font-size:14px;font-weight:600;color:#fff;background:#2563eb;border:none;border-radius:6px;cursor:pointer">Submit</button></form>' },
|
|
1833
|
+
{ name:'Input', icon:'bi-input-cursor-text', defaultAccSection:'size', html:'<input type="text" placeholder="Enter text" style="width:100%;max-width:320px;padding:8px 12px;font-size:14px;border:1px solid #cbd5e1;border-radius:6px;box-sizing:border-box">' },
|
|
1834
|
+
{ name:'Textarea', icon:'bi-textarea-resize', defaultAccSection:'size', html:'<textarea rows="3" placeholder="Enter text" style="width:100%;max-width:320px;padding:8px 12px;font-size:14px;border:1px solid #cbd5e1;border-radius:6px;box-sizing:border-box;resize:vertical"></textarea>' },
|
|
1835
|
+
{ name:'Select', icon:'bi-menu-button-wide', defaultAccSection:'size', html:'<select style="width:100%;max-width:320px;padding:8px 12px;font-size:14px;border:1px solid #cbd5e1;border-radius:6px;background:#fff;box-sizing:border-box"><option>Option 1</option><option>Option 2</option></select>' },
|
|
1836
|
+
{ name:'Card', icon:'bi-card-text', defaultAccSection:'shadow', html:'<div style="border:1px solid #e2e8f0;border-radius:8px;background:#fff;overflow:hidden;max-width:360px;box-shadow:0 1px 3px rgba(0,0,0,.08)"><div style="padding:20px"><h5 style="margin:0 0 8px;font-size:18px;font-weight:700;color:#0f172a">Card Title</h5><p style="margin:0 0 16px;font-size:14px;line-height:1.5;color:#475569">Card content here.</p><a href="#" style="display:inline-block;padding:8px 16px;font-size:14px;font-weight:600;color:#fff;background:#2563eb;border-radius:6px;text-decoration:none">Action</a></div></div>' },
|
|
1837
|
+
{ name:'Alert', icon:'bi-exclamation-triangle', defaultAccSection:'background', html:'<div role="alert" style="padding:12px 16px;font-size:14px;line-height:1.5;color:#0c4a6e;background:#e0f2fe;border:1px solid #7dd3fc;border-radius:6px">This is an alert message.</div>' },
|
|
1838
|
+
{ name:'Badge', icon:'bi-tag', defaultAccSection:'typography', html:'<span style="display:inline-flex;align-items:center;padding:4px 10px;font-size:12px;font-weight:600;line-height:1;letter-spacing:.02em;color:#fff;background:#2563eb;border-radius:999px">New</span>' },
|
|
1839
|
+
{ name:'Container', icon:'bi-layout-three-columns', defaultAccSection:'spacing', html:'<div style="width:100%;max-width:960px;margin:0 auto;padding:16px;box-sizing:border-box"><div style="display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px"><div style="padding:16px;background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px"><p style="margin:0">Column 1</p></div><div style="padding:16px;background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px"><p style="margin:0">Column 2</p></div><div style="padding:16px;background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px"><p style="margin:0">Column 3</p></div></div></div>' },
|
|
1840
|
+
{ name:'2 Cols', icon:'bi-layout-split', defaultAccSection:'spacing', html:'<div style="display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px;width:100%;box-sizing:border-box"><div style="padding:16px;background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px;min-height:80px;box-sizing:border-box"><p style="margin:0">Left column</p></div><div style="padding:16px;background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px;min-height:80px;box-sizing:border-box"><p style="margin:0">Right column</p></div></div>' },
|
|
1483
1841
|
];
|
|
1484
1842
|
|
|
1485
1843
|
// \u2500\u2500 PostMessage bridge \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
@@ -1633,7 +1991,7 @@ var leftPanelCollapsed = false;
|
|
|
1633
1991
|
var viewportPreset = 'desktop';
|
|
1634
1992
|
var viewportWidth = 1440;
|
|
1635
1993
|
var viewportHeight = 1024;
|
|
1636
|
-
var viewportZoom =
|
|
1994
|
+
var viewportZoom = null;
|
|
1637
1995
|
var selectedEl = null;
|
|
1638
1996
|
/** Stable selector fingerprint for resilient selection recovery after DOM churn. */
|
|
1639
1997
|
var selectedElFingerprint = '';
|
|
@@ -1653,6 +2011,7 @@ var iframeSyncRetryTimer = null;
|
|
|
1653
2011
|
var iframeSyncAttempts = 0;
|
|
1654
2012
|
var selectionScrollWin = null;
|
|
1655
2013
|
var selectionResizeBound = false;
|
|
2014
|
+
var selectionPanelScrollBound = false;
|
|
1656
2015
|
var clickAttachDoc = null;
|
|
1657
2016
|
var hoverAttachDoc = null;
|
|
1658
2017
|
var changeObserver = null;
|
|
@@ -1904,16 +2263,22 @@ function clampViewportNumber(v, fallback, min, max) {
|
|
|
1904
2263
|
|
|
1905
2264
|
function getViewportFitZoom() {
|
|
1906
2265
|
var panel = document.getElementById('iframe-panel');
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
2266
|
+
if (!panel || !viewportWidth || viewportWidth <= 0 || !viewportHeight || viewportHeight <= 0) return 1;
|
|
2267
|
+
var availW = Math.max(260, panel.clientWidth);
|
|
2268
|
+
var availH = Math.max(200, panel.clientHeight);
|
|
2269
|
+
return Math.min(1, availW / viewportWidth, availH / viewportHeight);
|
|
1910
2270
|
}
|
|
1911
2271
|
|
|
1912
2272
|
function getAppliedViewportZoom() {
|
|
1913
|
-
var
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
return Math.min(
|
|
2273
|
+
var fit = getViewportFitZoom();
|
|
2274
|
+
var z = viewportZoom != null ? Number(viewportZoom) : fit;
|
|
2275
|
+
if (!Number.isFinite(z) || z <= 0) z = fit;
|
|
2276
|
+
return Math.max(0.25, Math.min(2, z));
|
|
2277
|
+
}
|
|
2278
|
+
|
|
2279
|
+
function resetViewportZoomToFit() {
|
|
2280
|
+
viewportZoom = null;
|
|
2281
|
+
applyViewportFrame();
|
|
1917
2282
|
}
|
|
1918
2283
|
|
|
1919
2284
|
function updateViewportLabel() {
|
|
@@ -1934,20 +2299,28 @@ function syncViewportMenuControls() {
|
|
|
1934
2299
|
presetButtons[i].classList.toggle('active', key === viewportPreset);
|
|
1935
2300
|
}
|
|
1936
2301
|
}
|
|
1937
|
-
if (widthInp) widthInp.value = String(viewportWidth);
|
|
1938
|
-
if (heightInp) heightInp.value = String(viewportHeight);
|
|
2302
|
+
if (widthInp && document.activeElement !== widthInp) widthInp.value = String(viewportWidth);
|
|
2303
|
+
if (heightInp && document.activeElement !== heightInp) heightInp.value = String(viewportHeight);
|
|
1939
2304
|
if (zoomInp) zoomInp.value = String(Math.round(getAppliedViewportZoom() * 100));
|
|
1940
2305
|
}
|
|
1941
2306
|
|
|
1942
2307
|
function applyViewportFrame() {
|
|
1943
2308
|
var frame = document.getElementById('device-frame');
|
|
1944
2309
|
var iframe = document.getElementById('iframeId');
|
|
2310
|
+
var panel = document.getElementById('iframe-panel');
|
|
1945
2311
|
if (!frame) return;
|
|
1946
2312
|
frame.className = currentDevice;
|
|
1947
2313
|
frame.style.width = viewportWidth + 'px';
|
|
1948
2314
|
frame.style.height = viewportHeight + 'px';
|
|
1949
2315
|
frame.style.maxWidth = 'none';
|
|
1950
|
-
|
|
2316
|
+
var zoom = getAppliedViewportZoom();
|
|
2317
|
+
var fit = getViewportFitZoom();
|
|
2318
|
+
frame.style.zoom = String(zoom);
|
|
2319
|
+
if (panel) {
|
|
2320
|
+
var zoomedIn = zoom > fit + 0.001;
|
|
2321
|
+
panel.style.overflow = zoomedIn ? 'auto' : 'hidden';
|
|
2322
|
+
panel.style.alignItems = zoomedIn ? 'flex-start' : 'center';
|
|
2323
|
+
}
|
|
1951
2324
|
if (iframe) {
|
|
1952
2325
|
iframe.style.height = viewportHeight + 'px';
|
|
1953
2326
|
iframe.style.minHeight = viewportHeight + 'px';
|
|
@@ -1964,6 +2337,7 @@ function setViewportPreset(presetKey) {
|
|
|
1964
2337
|
viewportWidth = preset.width;
|
|
1965
2338
|
viewportHeight = preset.height;
|
|
1966
2339
|
currentDevice = preset.device || 'desktop';
|
|
2340
|
+
viewportZoom = null;
|
|
1967
2341
|
['desktop','tablet','mobile'].forEach(function(d) {
|
|
1968
2342
|
document.getElementById('dev-' + d).classList.toggle('active', d === currentDevice);
|
|
1969
2343
|
});
|
|
@@ -1976,20 +2350,26 @@ function setDevice(device) {
|
|
|
1976
2350
|
var preset = DEVICE_PRESETS[device] || DEVICE_PRESETS.desktop;
|
|
1977
2351
|
viewportWidth = preset.width;
|
|
1978
2352
|
viewportHeight = preset.height;
|
|
2353
|
+
viewportZoom = null;
|
|
1979
2354
|
['desktop','tablet','mobile'].forEach(function(d) {
|
|
1980
2355
|
document.getElementById('dev-' + d).classList.toggle('active', d === device);
|
|
1981
2356
|
});
|
|
1982
2357
|
applyViewportFrame();
|
|
1983
2358
|
}
|
|
1984
2359
|
|
|
1985
|
-
function setViewportCustomFromInputs() {
|
|
2360
|
+
function setViewportCustomFromInputs(opts) {
|
|
2361
|
+
opts = opts || {};
|
|
1986
2362
|
var widthInp = document.getElementById('dev-custom-width');
|
|
1987
2363
|
var heightInp = document.getElementById('dev-custom-height');
|
|
1988
|
-
var
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
2364
|
+
var rawW = widthInp ? widthInp.value : '';
|
|
2365
|
+
var rawH = heightInp ? heightInp.value : '';
|
|
2366
|
+
if (!opts.force) {
|
|
2367
|
+
if (widthInp && document.activeElement === widthInp && rawW === '') return;
|
|
2368
|
+
if (heightInp && document.activeElement === heightInp && rawH === '') return;
|
|
2369
|
+
}
|
|
2370
|
+
viewportWidth = clampViewportNumber(rawW, viewportWidth, 240, 3840);
|
|
2371
|
+
viewportHeight = clampViewportNumber(rawH, viewportHeight, 320, 3840);
|
|
2372
|
+
viewportZoom = null;
|
|
1993
2373
|
viewportPreset = 'custom';
|
|
1994
2374
|
currentDevice = viewportWidth <= 480 ? 'mobile' : (viewportWidth <= 1024 ? 'tablet' : 'desktop');
|
|
1995
2375
|
['desktop','tablet','mobile'].forEach(function(d) {
|
|
@@ -1998,6 +2378,22 @@ function setViewportCustomFromInputs() {
|
|
|
1998
2378
|
applyViewportFrame();
|
|
1999
2379
|
}
|
|
2000
2380
|
|
|
2381
|
+
var customViewportApplyTimer = null;
|
|
2382
|
+
function scheduleCustomViewportApply() {
|
|
2383
|
+
if (customViewportApplyTimer) clearTimeout(customViewportApplyTimer);
|
|
2384
|
+
customViewportApplyTimer = setTimeout(function() {
|
|
2385
|
+
customViewportApplyTimer = null;
|
|
2386
|
+
setViewportCustomFromInputs();
|
|
2387
|
+
}, 300);
|
|
2388
|
+
}
|
|
2389
|
+
function applyCustomViewportNow() {
|
|
2390
|
+
if (customViewportApplyTimer) {
|
|
2391
|
+
clearTimeout(customViewportApplyTimer);
|
|
2392
|
+
customViewportApplyTimer = null;
|
|
2393
|
+
}
|
|
2394
|
+
setViewportCustomFromInputs({ force: true });
|
|
2395
|
+
}
|
|
2396
|
+
|
|
2001
2397
|
function closeViewportMenu() {
|
|
2002
2398
|
var menu = document.getElementById('dev-more-menu');
|
|
2003
2399
|
if (!menu) return;
|
|
@@ -2018,8 +2414,10 @@ function bindViewportControls() {
|
|
|
2018
2414
|
var menu = document.getElementById('dev-more-menu');
|
|
2019
2415
|
var leftPanelToggleLabel = document.getElementById('left-panel-toggle-label');
|
|
2020
2416
|
var presetButtons = document.querySelectorAll('#dev-preset-list .vp-preset-btn');
|
|
2021
|
-
var
|
|
2417
|
+
var widthInp = document.getElementById('dev-custom-width');
|
|
2418
|
+
var heightInp = document.getElementById('dev-custom-height');
|
|
2022
2419
|
var zoomInp = document.getElementById('dev-zoom-level');
|
|
2420
|
+
var zoomFitBtn = document.getElementById('dev-zoom-fit-btn');
|
|
2023
2421
|
var viewportBtn = document.querySelector('.tb-viewport');
|
|
2024
2422
|
function updateLeftPanelToggleLabel() {
|
|
2025
2423
|
if (!leftPanelToggleLabel) return;
|
|
@@ -2049,11 +2447,21 @@ function bindViewportControls() {
|
|
|
2049
2447
|
e.stopPropagation();
|
|
2050
2448
|
toggleViewportMenu();
|
|
2051
2449
|
});
|
|
2052
|
-
if (
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2450
|
+
if (widthInp) {
|
|
2451
|
+
widthInp.addEventListener('input', scheduleCustomViewportApply);
|
|
2452
|
+
widthInp.addEventListener('change', applyCustomViewportNow);
|
|
2453
|
+
}
|
|
2454
|
+
if (heightInp) {
|
|
2455
|
+
heightInp.addEventListener('input', scheduleCustomViewportApply);
|
|
2456
|
+
heightInp.addEventListener('change', applyCustomViewportNow);
|
|
2457
|
+
}
|
|
2458
|
+
if (zoomFitBtn) {
|
|
2459
|
+
zoomFitBtn.addEventListener('click', function(e) {
|
|
2460
|
+
e.preventDefault();
|
|
2461
|
+
e.stopPropagation();
|
|
2462
|
+
resetViewportZoomToFit();
|
|
2463
|
+
});
|
|
2464
|
+
}
|
|
2057
2465
|
if (zoomInp) {
|
|
2058
2466
|
zoomInp.addEventListener('change', function() {
|
|
2059
2467
|
var z = clampViewportNumber(zoomInp.value, Math.round(getAppliedViewportZoom() * 100), 25, 200);
|
|
@@ -2088,7 +2496,7 @@ function bindViewportControls() {
|
|
|
2088
2496
|
function switchLeftTab(tab) {
|
|
2089
2497
|
if (tab !== 'elements' && tab !== 'dom-tree') return;
|
|
2090
2498
|
currentLeftTab = tab;
|
|
2091
|
-
var tabs = document.querySelectorAll('.lp-tabs .lp-tab');
|
|
2499
|
+
var tabs = document.querySelectorAll('#left-panel .lp-tabs .lp-tab');
|
|
2092
2500
|
for (var i = 0; i < tabs.length; i++) {
|
|
2093
2501
|
var oc = tabs[i].getAttribute('onclick') || '';
|
|
2094
2502
|
tabs[i].classList.toggle('active', oc.indexOf("switchLeftTab('" + tab + "')") >= 0);
|
|
@@ -2100,18 +2508,26 @@ function switchLeftTab(tab) {
|
|
|
2100
2508
|
}
|
|
2101
2509
|
var inp = document.getElementById('comp-search');
|
|
2102
2510
|
if (tab === 'elements') {
|
|
2103
|
-
inp.placeholder = 'Search elements\u2026';
|
|
2104
2511
|
renderElementsTree(inp.value);
|
|
2105
2512
|
} else if (tab === 'dom-tree') {
|
|
2106
|
-
inp.placeholder = 'Search layers\u2026';
|
|
2107
2513
|
renderDomTree(inp.value);
|
|
2108
2514
|
}
|
|
2109
2515
|
}
|
|
2110
2516
|
|
|
2517
|
+
function expandSectionComponentsBody() {
|
|
2518
|
+
var panel = document.getElementById('section-components-panel');
|
|
2519
|
+
if (!panel) return;
|
|
2520
|
+
var body = panel.querySelector('.lp-body');
|
|
2521
|
+
var toggle = panel.querySelector('.close-section-components-panel');
|
|
2522
|
+
if (body) body.classList.remove('collapsed');
|
|
2523
|
+
if (toggle) toggle.classList.remove('collapsed');
|
|
2524
|
+
}
|
|
2525
|
+
|
|
2111
2526
|
function switchSectionComponentsTab(tab) {
|
|
2112
2527
|
if (tab !== 'components' && tab !== 'sections') return;
|
|
2528
|
+
expandSectionComponentsBody();
|
|
2113
2529
|
currentSectionComponentsTab = tab;
|
|
2114
|
-
var tabs = document.querySelectorAll('
|
|
2530
|
+
var tabs = document.querySelectorAll('#section-components-panel .lp-tabs .lp-tab');
|
|
2115
2531
|
for (var i = 0; i < tabs.length; i++) {
|
|
2116
2532
|
var oc = tabs[i].getAttribute('onclick') || '';
|
|
2117
2533
|
tabs[i].classList.toggle('active', oc.indexOf("switchSectionComponentsTab('" + tab + "')") >= 0);
|
|
@@ -2121,29 +2537,67 @@ function switchSectionComponentsTab(tab) {
|
|
|
2121
2537
|
if (compPane) compPane.classList.toggle('active', tab === 'components');
|
|
2122
2538
|
if (secPane) secPane.classList.toggle('active', tab === 'sections');
|
|
2123
2539
|
var inp = document.getElementById('comp-search');
|
|
2124
|
-
if (inp) inp.placeholder = tab === 'sections' ? 'Search
|
|
2540
|
+
if (inp) inp.placeholder = tab === 'sections' ? 'Search' : 'Search';
|
|
2125
2541
|
renderSidebar(inp ? inp.value : '');
|
|
2126
2542
|
}
|
|
2127
2543
|
|
|
2544
|
+
function toggleSectionComponentsBody() {
|
|
2545
|
+
var panel = document.getElementById('section-components-panel');
|
|
2546
|
+
if (!panel) return;
|
|
2547
|
+
var body = panel.querySelector('.lp-body');
|
|
2548
|
+
var toggle = panel.querySelector('.close-section-components-panel');
|
|
2549
|
+
if (!body) return;
|
|
2550
|
+
var collapsed = body.classList.toggle('collapsed');
|
|
2551
|
+
if (toggle) toggle.classList.toggle('collapsed', collapsed);
|
|
2552
|
+
}
|
|
2553
|
+
|
|
2128
2554
|
function toggleSectionComponentsPanel(forceVisible) {
|
|
2129
2555
|
var panel = document.getElementById('section-components-panel');
|
|
2130
2556
|
if (!panel) return;
|
|
2131
|
-
var
|
|
2557
|
+
var body = panel.querySelector('.lp-body');
|
|
2558
|
+
var toggle = panel.querySelector('.close-section-components-panel');
|
|
2559
|
+
if (!body) return;
|
|
2560
|
+
var isCollapsed = body.classList.contains('collapsed');
|
|
2561
|
+
var shouldExpand =
|
|
2132
2562
|
typeof forceVisible === 'boolean'
|
|
2133
2563
|
? forceVisible
|
|
2134
|
-
:
|
|
2135
|
-
|
|
2136
|
-
if (
|
|
2564
|
+
: isCollapsed;
|
|
2565
|
+
body.classList.toggle('collapsed', !shouldExpand);
|
|
2566
|
+
if (toggle) toggle.classList.toggle('collapsed', !shouldExpand);
|
|
2567
|
+
if (shouldExpand) {
|
|
2137
2568
|
switchSectionComponentsTab(currentSectionComponentsTab || 'components');
|
|
2138
2569
|
}
|
|
2139
2570
|
}
|
|
2140
2571
|
|
|
2572
|
+
function handleAddElementClick(e) {
|
|
2573
|
+
if (e) {
|
|
2574
|
+
e.preventDefault();
|
|
2575
|
+
e.stopPropagation();
|
|
2576
|
+
}
|
|
2577
|
+
toggleSectionComponentsPanel();
|
|
2578
|
+
}
|
|
2579
|
+
|
|
2141
2580
|
// \u2500\u2500 Accordion toggle \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
2142
2581
|
function toggleAcc(name) {
|
|
2143
2582
|
var sec = document.getElementById('acc-' + name);
|
|
2144
2583
|
if (sec) sec.classList.toggle('open');
|
|
2145
2584
|
}
|
|
2146
2585
|
|
|
2586
|
+
function focusDesignAccordionSection(name) {
|
|
2587
|
+
if (!name) return;
|
|
2588
|
+
if (currentMainTab !== 'design') switchMainTab('design');
|
|
2589
|
+
var sec = document.getElementById('acc-' + name);
|
|
2590
|
+
if (!sec || sec.style.display === 'none') return;
|
|
2591
|
+
sec.classList.add('open');
|
|
2592
|
+
requestAnimationFrame(function() {
|
|
2593
|
+
try {
|
|
2594
|
+
sec.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
|
2595
|
+
} catch(_) {
|
|
2596
|
+
sec.scrollIntoView(true);
|
|
2597
|
+
}
|
|
2598
|
+
});
|
|
2599
|
+
}
|
|
2600
|
+
|
|
2147
2601
|
// \u2500\u2500 Main tab switching (Design / States / History) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
2148
2602
|
function switchMainTab(tab) {
|
|
2149
2603
|
currentMainTab = tab;
|
|
@@ -2208,9 +2662,19 @@ var PROP_META = {
|
|
|
2208
2662
|
'pp-id': {label:'ID', cssProp:null},
|
|
2209
2663
|
'pp-href': {label:'Href', cssProp:null},
|
|
2210
2664
|
'pp-target': {label:'Target', cssProp:null},
|
|
2665
|
+
'pp-rel': {label:'Rel', cssProp:null},
|
|
2666
|
+
'pp-download':{label:'Download', cssProp:null},
|
|
2667
|
+
'pp-link-title': {label:'Title', cssProp:null},
|
|
2668
|
+
'pp-hreflang':{label:'Hreflang', cssProp:null},
|
|
2669
|
+
'pp-link-type': {label:'Link type', cssProp:null},
|
|
2670
|
+
'pp-referrerpolicy': {label:'Referrer policy', cssProp:null},
|
|
2211
2671
|
'pp-src': {label:'Src', cssProp:null},
|
|
2672
|
+
'pp-video-src': {label:'Src', cssProp:null},
|
|
2673
|
+
'pp-youtube-id': {label:'YouTube video ID', cssProp:null},
|
|
2674
|
+
'pp-vimeo-id': {label:'Vimeo video ID', cssProp:null},
|
|
2212
2675
|
'pp-alt': {label:'Alt', cssProp:null},
|
|
2213
2676
|
'pp-ph': {label:'Placeholder', cssProp:null},
|
|
2677
|
+
'pp-value': {label:'Value', cssProp:null},
|
|
2214
2678
|
'pp-text': {label:'Inner text', cssProp:null},
|
|
2215
2679
|
'pp-html': {label:'Inner HTML', cssProp:null},
|
|
2216
2680
|
'pp-mob-css': {label:'Mobile CSS', cssProp:null},
|
|
@@ -2233,9 +2697,19 @@ function getOriginalValue(inputId, el) {
|
|
|
2233
2697
|
case 'pp-id': return el.id || '';
|
|
2234
2698
|
case 'pp-href': return el.getAttribute('href') || '';
|
|
2235
2699
|
case 'pp-target': return el.getAttribute('target') || '';
|
|
2700
|
+
case 'pp-rel': return el.getAttribute('rel') || '';
|
|
2701
|
+
case 'pp-download': return el.getAttribute('download') || '';
|
|
2702
|
+
case 'pp-link-title': return el.getAttribute('title') || '';
|
|
2703
|
+
case 'pp-hreflang': return el.getAttribute('hreflang') || '';
|
|
2704
|
+
case 'pp-link-type': return el.getAttribute('type') || '';
|
|
2705
|
+
case 'pp-referrerpolicy': return el.getAttribute('referrerpolicy') || '';
|
|
2236
2706
|
case 'pp-src': return el.getAttribute('src') || '';
|
|
2707
|
+
case 'pp-video-src': return getVideoSrc(el);
|
|
2708
|
+
case 'pp-youtube-id': return getYoutubeVideoId(el);
|
|
2709
|
+
case 'pp-vimeo-id': return getVimeoVideoId(el);
|
|
2237
2710
|
case 'pp-alt': return el.getAttribute('alt') || '';
|
|
2238
2711
|
case 'pp-ph': return el.getAttribute('placeholder') || '';
|
|
2712
|
+
case 'pp-value': return getFormControlValue(el);
|
|
2239
2713
|
case 'pp-css': return el.getAttribute('style') || '';
|
|
2240
2714
|
case 'pp-mob-css': return el.dataset.mobileCss || '';
|
|
2241
2715
|
case 'pp-tab-css': return el.dataset.tabletCss || '';
|
|
@@ -2372,9 +2846,19 @@ function revertChangeOnDom(change) {
|
|
|
2372
2846
|
case 'pp-css': orig ? el.setAttribute('style', orig) : el.removeAttribute('style'); break;
|
|
2373
2847
|
case 'pp-href': orig ? el.setAttribute('href', orig) : el.removeAttribute('href'); break;
|
|
2374
2848
|
case 'pp-target': orig ? el.setAttribute('target', orig) : el.removeAttribute('target'); break;
|
|
2849
|
+
case 'pp-rel': orig ? el.setAttribute('rel', orig) : el.removeAttribute('rel'); break;
|
|
2850
|
+
case 'pp-download': orig ? el.setAttribute('download', orig) : el.removeAttribute('download'); break;
|
|
2851
|
+
case 'pp-link-title': orig ? el.setAttribute('title', orig) : el.removeAttribute('title'); break;
|
|
2852
|
+
case 'pp-hreflang': orig ? el.setAttribute('hreflang', orig) : el.removeAttribute('hreflang'); break;
|
|
2853
|
+
case 'pp-link-type': orig ? el.setAttribute('type', orig) : el.removeAttribute('type'); break;
|
|
2854
|
+
case 'pp-referrerpolicy': orig ? el.setAttribute('referrerpolicy', orig) : el.removeAttribute('referrerpolicy'); break;
|
|
2375
2855
|
case 'pp-src': orig ? el.setAttribute('src', orig) : el.removeAttribute('src'); break;
|
|
2856
|
+
case 'pp-video-src': orig ? setVideoSrc(el, orig) : setVideoSrc(el, ''); break;
|
|
2857
|
+
case 'pp-youtube-id': orig ? setYoutubeVideoId(el, orig) : setYoutubeVideoId(el, ''); break;
|
|
2858
|
+
case 'pp-vimeo-id': orig ? setVimeoVideoId(el, orig) : setVimeoVideoId(el, ''); break;
|
|
2376
2859
|
case 'pp-alt': orig ? el.setAttribute('alt', orig) : el.removeAttribute('alt'); break;
|
|
2377
2860
|
case 'pp-ph': orig ? el.setAttribute('placeholder', orig) : el.removeAttribute('placeholder'); break;
|
|
2861
|
+
case 'pp-value': el.value = orig; break;
|
|
2378
2862
|
case 'pp-mob-css': el.dataset.mobileCss = orig; break;
|
|
2379
2863
|
case 'pp-tab-css': el.dataset.tabletCss = orig; break;
|
|
2380
2864
|
default: console.warn('[V2] revertChangeOnDom: no revert handler for', change.inputId);
|
|
@@ -2398,11 +2882,28 @@ function syncDesignInput(change) {
|
|
|
2398
2882
|
function removeStateChange(idx) {
|
|
2399
2883
|
var change = stateChanges[idx];
|
|
2400
2884
|
if (!change) return;
|
|
2885
|
+
if (
|
|
2886
|
+
change.isStructuralLive &&
|
|
2887
|
+
normalizeChangesetType({ type: change.structuralType }) === 'insert'
|
|
2888
|
+
) {
|
|
2889
|
+
var instId = historyInsertInstanceId(null, change);
|
|
2890
|
+
if (instId) {
|
|
2891
|
+
removeEditorInsertByInstanceId(instId);
|
|
2892
|
+
commitStateChangesForActiveVariation();
|
|
2893
|
+
renderStatesTab();
|
|
2894
|
+
if (currentMainTab === 'history') renderHistoryTab();
|
|
2895
|
+
try {
|
|
2896
|
+
delete varHtmlCache[activeVarId];
|
|
2897
|
+
} catch(_) {}
|
|
2898
|
+
saveCurrentVariationHtml();
|
|
2899
|
+
recomputeEditorDirty();
|
|
2900
|
+
scheduleDomTreeRefresh();
|
|
2901
|
+
return;
|
|
2902
|
+
}
|
|
2903
|
+
}
|
|
2401
2904
|
if (change.isStructuralLive) {
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
change.vveTs,
|
|
2405
|
-
);
|
|
2905
|
+
var varId = change.structuralVarId || activeVarId;
|
|
2906
|
+
removeSessionStructuralRowByTimestamp(varId, change.vveTs);
|
|
2406
2907
|
stateChanges.splice(idx, 1);
|
|
2407
2908
|
commitStateChangesForActiveVariation();
|
|
2408
2909
|
renderStatesTab();
|
|
@@ -2500,10 +3001,28 @@ function captureChangesetSnapshotBeforeApply(entry, el, iframeDoc) {
|
|
|
2500
3001
|
break;
|
|
2501
3002
|
case 'attribute':
|
|
2502
3003
|
if (entry.attribute) {
|
|
3004
|
+
var attrVal = el.getAttribute(entry.attribute);
|
|
3005
|
+
if (
|
|
3006
|
+
String(entry.attribute).toLowerCase() === 'src' &&
|
|
3007
|
+
el.tagName &&
|
|
3008
|
+
el.tagName.toLowerCase() === 'video'
|
|
3009
|
+
) {
|
|
3010
|
+
attrVal = getVideoSrc(el);
|
|
3011
|
+
} else if (
|
|
3012
|
+
String(entry.attribute).toLowerCase() === 'data-youtube-id' &&
|
|
3013
|
+
isYoutubeVideoElement(el)
|
|
3014
|
+
) {
|
|
3015
|
+
attrVal = getYoutubeVideoId(el);
|
|
3016
|
+
} else if (
|
|
3017
|
+
String(entry.attribute).toLowerCase() === 'data-vimeo-id' &&
|
|
3018
|
+
isVimeoVideoElement(el)
|
|
3019
|
+
) {
|
|
3020
|
+
attrVal = getVimeoVideoId(el);
|
|
3021
|
+
}
|
|
2503
3022
|
appliedChangesetSnapshots[k] = {
|
|
2504
3023
|
kind: 'attribute',
|
|
2505
3024
|
name: entry.attribute,
|
|
2506
|
-
v:
|
|
3025
|
+
v: attrVal,
|
|
2507
3026
|
};
|
|
2508
3027
|
}
|
|
2509
3028
|
break;
|
|
@@ -2552,6 +3071,13 @@ function revertChangesetEntryOnDom(entry) {
|
|
|
2552
3071
|
var iframeDoc = document.getElementById('iframeId').contentDocument;
|
|
2553
3072
|
if (!iframeDoc) return false;
|
|
2554
3073
|
var k = entrySnapshotKey(entry);
|
|
3074
|
+
if (normalizeChangesetType(entry) === 'insert') {
|
|
3075
|
+
var instId = instanceIdFromInsertHtml(entry.html);
|
|
3076
|
+
delete appliedChangesetSnapshots[k];
|
|
3077
|
+
if (instId && removeEditorInsertByInstanceId(instId)) return false;
|
|
3078
|
+
softReloadEditorIframe();
|
|
3079
|
+
return true;
|
|
3080
|
+
}
|
|
2555
3081
|
var snap = appliedChangesetSnapshots[k];
|
|
2556
3082
|
var el = querySelectorResolved(iframeDoc, entry.selector);
|
|
2557
3083
|
if (!snap || !el) {
|
|
@@ -2570,7 +3096,23 @@ function revertChangesetEntryOnDom(entry) {
|
|
|
2570
3096
|
if (snap.v) el.setAttribute('style', snap.v);
|
|
2571
3097
|
else el.removeAttribute('style');
|
|
2572
3098
|
} else if (snap.kind === 'attribute' && snap.name) {
|
|
2573
|
-
if (
|
|
3099
|
+
if (
|
|
3100
|
+
String(snap.name).toLowerCase() === 'src' &&
|
|
3101
|
+
el.tagName &&
|
|
3102
|
+
el.tagName.toLowerCase() === 'video'
|
|
3103
|
+
) {
|
|
3104
|
+
setVideoSrc(el, snap.v == null ? '' : snap.v);
|
|
3105
|
+
} else if (
|
|
3106
|
+
String(snap.name).toLowerCase() === 'data-youtube-id' &&
|
|
3107
|
+
isYoutubeVideoElement(el)
|
|
3108
|
+
) {
|
|
3109
|
+
setYoutubeVideoId(el, snap.v == null ? '' : snap.v);
|
|
3110
|
+
} else if (
|
|
3111
|
+
String(snap.name).toLowerCase() === 'data-vimeo-id' &&
|
|
3112
|
+
isVimeoVideoElement(el)
|
|
3113
|
+
) {
|
|
3114
|
+
setVimeoVideoId(el, snap.v == null ? '' : snap.v);
|
|
3115
|
+
} else if (snap.v == null || snap.v === '') el.removeAttribute(snap.name);
|
|
2574
3116
|
else el.setAttribute(snap.name, snap.v);
|
|
2575
3117
|
} else if (snap.kind === 'display') el.style.display = snap.v;
|
|
2576
3118
|
else {
|
|
@@ -2651,6 +3193,42 @@ function formatHistoryRelativeTime(ts) {
|
|
|
2651
3193
|
return day + ' day' + (day === 1 ? '' : 's') + ' ago';
|
|
2652
3194
|
}
|
|
2653
3195
|
|
|
3196
|
+
function findSessionInsertRowForChange(change) {
|
|
3197
|
+
if (!change) return null;
|
|
3198
|
+
var varId = change.structuralVarId || activeVarId;
|
|
3199
|
+
var arr = varId && sessionStructuralChainRowsByVarId[varId];
|
|
3200
|
+
if (!arr || !arr.length) return null;
|
|
3201
|
+
var instId = '';
|
|
3202
|
+
try {
|
|
3203
|
+
if (change.targetEl && change.targetEl.getAttribute) {
|
|
3204
|
+
instId = change.targetEl.getAttribute('data-vve-instance') || '';
|
|
3205
|
+
}
|
|
3206
|
+
} catch(_) {}
|
|
3207
|
+
for (var i = 0; i < arr.length; i++) {
|
|
3208
|
+
var row = arr[i];
|
|
3209
|
+
if (!row || normalizeChangesetType(row) !== 'insert') continue;
|
|
3210
|
+
if (change.vveTs && row.vveTs === change.vveTs) return row;
|
|
3211
|
+
if (instId && instanceIdFromInsertHtml(row.html) === instId) return row;
|
|
3212
|
+
}
|
|
3213
|
+
return null;
|
|
3214
|
+
}
|
|
3215
|
+
|
|
3216
|
+
function historyInsertInstanceId(entry, change) {
|
|
3217
|
+
if (entry && normalizeChangesetType(entry) === 'insert') {
|
|
3218
|
+
return instanceIdFromInsertHtml(entry.html);
|
|
3219
|
+
}
|
|
3220
|
+
if (change && change.isStructuralLive && normalizeChangesetType({ type: change.structuralType }) === 'insert') {
|
|
3221
|
+
var row = findSessionInsertRowForChange(change);
|
|
3222
|
+
if (row) return instanceIdFromInsertHtml(row.html);
|
|
3223
|
+
try {
|
|
3224
|
+
if (change.targetEl && change.targetEl.getAttribute) {
|
|
3225
|
+
return change.targetEl.getAttribute('data-vve-instance') || '';
|
|
3226
|
+
}
|
|
3227
|
+
} catch(_) {}
|
|
3228
|
+
}
|
|
3229
|
+
return '';
|
|
3230
|
+
}
|
|
3231
|
+
|
|
2654
3232
|
function getUnifiedHistoryItems() {
|
|
2655
3233
|
var out = [];
|
|
2656
3234
|
var v = getActiveVariationForHistory();
|
|
@@ -2660,6 +3238,7 @@ function getUnifiedHistoryItems() {
|
|
|
2660
3238
|
out.push({
|
|
2661
3239
|
source: 'saved',
|
|
2662
3240
|
idx: i,
|
|
3241
|
+
insertInstanceId: historyInsertInstanceId(e, null),
|
|
2663
3242
|
selector: (e && e.selector) || '(unknown)',
|
|
2664
3243
|
label: historyEntryTypeLabel(e),
|
|
2665
3244
|
value: historyEntryValuePreview(e),
|
|
@@ -2676,6 +3255,7 @@ function getUnifiedHistoryItems() {
|
|
|
2676
3255
|
out.push({
|
|
2677
3256
|
source: 'live',
|
|
2678
3257
|
idx: j,
|
|
3258
|
+
insertInstanceId: historyInsertInstanceId(null, c),
|
|
2679
3259
|
selector: c.selector || '(unknown)',
|
|
2680
3260
|
label: c.label || 'Live change',
|
|
2681
3261
|
value: c.value != null ? String(c.value).slice(0, 120) : '',
|
|
@@ -2709,11 +3289,15 @@ function renderHistoryTab() {
|
|
|
2709
3289
|
var title = 'Edit - ' + (it.label || 'Change');
|
|
2710
3290
|
var avatarLabel = it.source === 'live' ? 'Y' : 'S';
|
|
2711
3291
|
var timeText = formatHistoryRelativeTime(it.ts) || (it.tsLabel || '');
|
|
3292
|
+
var removeOnclick = it.insertInstanceId
|
|
3293
|
+
? 'removeHistoryItem("' + esc(it.source) + '",' + it.idx + ', event, "' + esc(it.insertInstanceId) + '")'
|
|
3294
|
+
: 'removeHistoryItem("' + esc(it.source) + '",' + it.idx + ', event)';
|
|
2712
3295
|
html +=
|
|
2713
3296
|
'<div class="history-item" role="button" tabindex="0" title="Jump to element in iframe" onclick="focusHistoryItem("' +
|
|
2714
3297
|
esc(it.source) +
|
|
2715
3298
|
'",' +
|
|
2716
3299
|
it.idx +
|
|
3300
|
+
(it.insertInstanceId ? ', "' + esc(it.insertInstanceId) + '"' : '') +
|
|
2717
3301
|
')">' +
|
|
2718
3302
|
'<span class="history-dot"></span>' +
|
|
2719
3303
|
'<div class="history-card">' +
|
|
@@ -2724,18 +3308,16 @@ function renderHistoryTab() {
|
|
|
2724
3308
|
'</div>' +
|
|
2725
3309
|
'<div class="history-time">' + esc(timeText || 'n/a') + '</div>' +
|
|
2726
3310
|
'</div>' +
|
|
2727
|
-
'<button type="button" class="state-remove history-remove" title="Remove this change" onclick="
|
|
2728
|
-
|
|
2729
|
-
'
|
|
2730
|
-
it.idx +
|
|
2731
|
-
', event)">✕</button>' +
|
|
3311
|
+
'<button type="button" class="state-remove history-remove" title="Remove this change" onclick="' +
|
|
3312
|
+
removeOnclick +
|
|
3313
|
+
'">✕</button>' +
|
|
2732
3314
|
'</div>';
|
|
2733
3315
|
}
|
|
2734
3316
|
html += '</div>';
|
|
2735
3317
|
container.innerHTML = html;
|
|
2736
3318
|
}
|
|
2737
3319
|
|
|
2738
|
-
function focusHistoryItem(source, idx) {
|
|
3320
|
+
function focusHistoryItem(source, idx, insertInstanceId) {
|
|
2739
3321
|
if (source === 'live') {
|
|
2740
3322
|
var change = stateChanges[idx];
|
|
2741
3323
|
if (!change || !change.selector) return;
|
|
@@ -2743,6 +3325,20 @@ function focusHistoryItem(source, idx) {
|
|
|
2743
3325
|
var iframe = document.getElementById('iframeId');
|
|
2744
3326
|
var iframeDoc = iframe && iframe.contentDocument;
|
|
2745
3327
|
if (!iframeDoc) return;
|
|
3328
|
+
var instId = insertInstanceId || historyInsertInstanceId(null, change);
|
|
3329
|
+
if (instId) {
|
|
3330
|
+
var safeInst = String(instId).split('"').join('\\"');
|
|
3331
|
+
var insertedEl = iframeDoc.querySelector('[data-vve-instance="' + safeInst + '"]');
|
|
3332
|
+
if (insertedEl) {
|
|
3333
|
+
selectElement(insertedEl);
|
|
3334
|
+
try {
|
|
3335
|
+
insertedEl.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'nearest' });
|
|
3336
|
+
} catch(_) {
|
|
3337
|
+
insertedEl.scrollIntoView();
|
|
3338
|
+
}
|
|
3339
|
+
return;
|
|
3340
|
+
}
|
|
3341
|
+
}
|
|
2746
3342
|
var el = querySelectorResolved(iframeDoc, change.selector);
|
|
2747
3343
|
if (!el) return;
|
|
2748
3344
|
selectElement(el);
|
|
@@ -2754,12 +3350,25 @@ function focusHistoryItem(source, idx) {
|
|
|
2754
3350
|
} catch(_) {}
|
|
2755
3351
|
return;
|
|
2756
3352
|
}
|
|
2757
|
-
focusHistoryChangeset(idx);
|
|
3353
|
+
focusHistoryChangeset(idx, insertInstanceId);
|
|
2758
3354
|
}
|
|
2759
3355
|
|
|
2760
|
-
function removeHistoryItem(source, idx, evt) {
|
|
3356
|
+
function removeHistoryItem(source, idx, evt, insertInstanceId) {
|
|
3357
|
+
if (evt && evt.stopPropagation) evt.stopPropagation();
|
|
3358
|
+
if (insertInstanceId) {
|
|
3359
|
+
removeEditorInsertByInstanceId(insertInstanceId);
|
|
3360
|
+
commitStateChangesForActiveVariation();
|
|
3361
|
+
try {
|
|
3362
|
+
delete varHtmlCache[activeVarId];
|
|
3363
|
+
} catch(_) {}
|
|
3364
|
+
saveCurrentVariationHtml();
|
|
3365
|
+
recomputeEditorDirty();
|
|
3366
|
+
if (currentMainTab === 'states') renderStatesTab();
|
|
3367
|
+
if (currentMainTab === 'history') renderHistoryTab();
|
|
3368
|
+
scheduleDomTreeRefresh();
|
|
3369
|
+
return;
|
|
3370
|
+
}
|
|
2761
3371
|
if (source === 'live') {
|
|
2762
|
-
if (evt && evt.stopPropagation) evt.stopPropagation();
|
|
2763
3372
|
removeStateChange(idx);
|
|
2764
3373
|
if (currentMainTab === 'history') renderHistoryTab();
|
|
2765
3374
|
return;
|
|
@@ -2798,7 +3407,7 @@ function isStyleOnlyChangesetEntry(entry) {
|
|
|
2798
3407
|
return false;
|
|
2799
3408
|
}
|
|
2800
3409
|
|
|
2801
|
-
function focusHistoryChangeset(idx) {
|
|
3410
|
+
function focusHistoryChangeset(idx, insertInstanceId) {
|
|
2802
3411
|
var v = getActiveVariationForHistory();
|
|
2803
3412
|
if (!v) return;
|
|
2804
3413
|
var arr = parseVariationChangesets(v);
|
|
@@ -2809,6 +3418,20 @@ function focusHistoryChangeset(idx) {
|
|
|
2809
3418
|
var iframe = document.getElementById('iframeId');
|
|
2810
3419
|
var iframeDoc = iframe && iframe.contentDocument;
|
|
2811
3420
|
if (!iframeDoc) return;
|
|
3421
|
+
var instId = insertInstanceId || historyInsertInstanceId(entry, null);
|
|
3422
|
+
if (instId) {
|
|
3423
|
+
var safeInst = String(instId).split('"').join('\\"');
|
|
3424
|
+
var insertedEl = iframeDoc.querySelector('[data-vve-instance="' + safeInst + '"]');
|
|
3425
|
+
if (insertedEl) {
|
|
3426
|
+
selectElement(insertedEl);
|
|
3427
|
+
try {
|
|
3428
|
+
insertedEl.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'nearest' });
|
|
3429
|
+
} catch(_) {
|
|
3430
|
+
insertedEl.scrollIntoView();
|
|
3431
|
+
}
|
|
3432
|
+
return;
|
|
3433
|
+
}
|
|
3434
|
+
}
|
|
2812
3435
|
var el = querySelectorResolved(iframeDoc, entry.selector);
|
|
2813
3436
|
if (!el) return;
|
|
2814
3437
|
selectElement(el);
|
|
@@ -2850,6 +3473,10 @@ function removeHistoryChangeset(idx, evt) {
|
|
|
2850
3473
|
var removedIsStructural = removedType === 'insert' || removedType === 'reorder';
|
|
2851
3474
|
if (didReload) {
|
|
2852
3475
|
/* revertChangesetEntryOnDom already kicked off iframe reload */
|
|
3476
|
+
} else if (removedType === 'insert') {
|
|
3477
|
+
try {
|
|
3478
|
+
saveCurrentVariationHtml();
|
|
3479
|
+
} catch(_) {}
|
|
2853
3480
|
} else if (removedIsStructural) {
|
|
2854
3481
|
softReloadEditorIframe();
|
|
2855
3482
|
} else if (hasStructuralRemaining) {
|
|
@@ -3518,6 +4145,14 @@ function loadPage(proxyUrl) {
|
|
|
3518
4145
|
// \u2500\u2500 Variation management \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
3519
4146
|
var VAR_COLORS = ['#0069A8','#CA3500','#00786F','#ec4899','#14b8a6','#f59e0b','#8b5cf6','#ef4444'];
|
|
3520
4147
|
|
|
4148
|
+
function varColorAlpha(hex, alpha) {
|
|
4149
|
+
var h = hex.slice(1);
|
|
4150
|
+
return 'rgba(' +
|
|
4151
|
+
parseInt(h.slice(0, 2), 16) + ',' +
|
|
4152
|
+
parseInt(h.slice(2, 4), 16) + ',' +
|
|
4153
|
+
parseInt(h.slice(4, 6), 16) + ',' + alpha + ')';
|
|
4154
|
+
}
|
|
4155
|
+
|
|
3521
4156
|
function renderVariationTabs() {
|
|
3522
4157
|
var container = document.getElementById('variation-tabs');
|
|
3523
4158
|
container.innerHTML = '';
|
|
@@ -3529,7 +4164,12 @@ function renderVariationTabs() {
|
|
|
3529
4164
|
btn.onclick = function() { switchVariation(v._id); };
|
|
3530
4165
|
var dot = document.createElement('span');
|
|
3531
4166
|
dot.className = 'var-dot';
|
|
3532
|
-
|
|
4167
|
+
var color = VAR_COLORS[i % VAR_COLORS.length];
|
|
4168
|
+
btn.setAttribute('data-color', color);
|
|
4169
|
+
btn.style.setProperty('--var-tab-color', color);
|
|
4170
|
+
dot.setAttribute('data-color', color);
|
|
4171
|
+
dot.style.background = color;
|
|
4172
|
+
dot.style.boxShadow = '0 0 0 3px ' + varColorAlpha(color, 0.5);
|
|
3533
4173
|
btn.appendChild(dot);
|
|
3534
4174
|
btn.appendChild(document.createTextNode(label));
|
|
3535
4175
|
container.appendChild(btn);
|
|
@@ -3730,6 +4370,29 @@ function removeSessionStructuralRowByTimestamp(varId, ts) {
|
|
|
3730
4370
|
}
|
|
3731
4371
|
}
|
|
3732
4372
|
|
|
4373
|
+
function removeStructuralStateChangeByTimestamp(varId, ts) {
|
|
4374
|
+
if (!varId || !ts) return;
|
|
4375
|
+
for (var i = stateChanges.length - 1; i >= 0; i--) {
|
|
4376
|
+
var c = stateChanges[i];
|
|
4377
|
+
if (
|
|
4378
|
+
c &&
|
|
4379
|
+
c.isStructuralLive &&
|
|
4380
|
+
c.vveTs === ts &&
|
|
4381
|
+
(c.structuralVarId || activeVarId) === varId
|
|
4382
|
+
) {
|
|
4383
|
+
stateChanges.splice(i, 1);
|
|
4384
|
+
}
|
|
4385
|
+
}
|
|
4386
|
+
}
|
|
4387
|
+
|
|
4388
|
+
/** Undo a session insert when its root node is deleted \u2014 avoids orphan remove rows that match re-inserts at the same slot. */
|
|
4389
|
+
function cancelSessionInsertForElement(varId, el) {
|
|
4390
|
+
if (!varId || !el) return false;
|
|
4391
|
+
var inst = el.getAttribute && el.getAttribute('data-vve-instance');
|
|
4392
|
+
if (!inst || !String(inst).trim()) return false;
|
|
4393
|
+
return removeEditorInsertByInstanceId(inst, { skipDom: true, varId: varId });
|
|
4394
|
+
}
|
|
4395
|
+
|
|
3733
4396
|
/** One States-tab row -> Conversion.io chain-set shape (matches applyChangesetEntry). */
|
|
3734
4397
|
function stateChangeToChainSet(c) {
|
|
3735
4398
|
if (!c || !c.selector) return null;
|
|
@@ -3755,12 +4418,32 @@ function stateChangeToChainSet(c) {
|
|
|
3755
4418
|
return { selector: c.selector, type: 'attribute', attribute: 'href', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
3756
4419
|
case 'pp-target':
|
|
3757
4420
|
return { selector: c.selector, type: 'attribute', attribute: 'target', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4421
|
+
case 'pp-rel':
|
|
4422
|
+
return { selector: c.selector, type: 'attribute', attribute: 'rel', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4423
|
+
case 'pp-download':
|
|
4424
|
+
return { selector: c.selector, type: 'attribute', attribute: 'download', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4425
|
+
case 'pp-link-title':
|
|
4426
|
+
return { selector: c.selector, type: 'attribute', attribute: 'title', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4427
|
+
case 'pp-hreflang':
|
|
4428
|
+
return { selector: c.selector, type: 'attribute', attribute: 'hreflang', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4429
|
+
case 'pp-link-type':
|
|
4430
|
+
return { selector: c.selector, type: 'attribute', attribute: 'type', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4431
|
+
case 'pp-referrerpolicy':
|
|
4432
|
+
return { selector: c.selector, type: 'attribute', attribute: 'referrerpolicy', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
3758
4433
|
case 'pp-src':
|
|
3759
4434
|
return { selector: c.selector, type: 'attribute', attribute: 'src', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4435
|
+
case 'pp-video-src':
|
|
4436
|
+
return { selector: c.selector, type: 'attribute', attribute: 'src', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4437
|
+
case 'pp-youtube-id':
|
|
4438
|
+
return { selector: c.selector, type: 'attribute', attribute: 'data-youtube-id', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4439
|
+
case 'pp-vimeo-id':
|
|
4440
|
+
return { selector: c.selector, type: 'attribute', attribute: 'data-vimeo-id', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
3760
4441
|
case 'pp-alt':
|
|
3761
4442
|
return { selector: c.selector, type: 'attribute', attribute: 'alt', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
3762
4443
|
case 'pp-ph':
|
|
3763
4444
|
return { selector: c.selector, type: 'attribute', attribute: 'placeholder', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4445
|
+
case 'pp-value':
|
|
4446
|
+
return { selector: c.selector, type: 'attribute', attribute: 'value', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
3764
4447
|
case 'pp-css':
|
|
3765
4448
|
return { selector: c.selector, type: 'attribute', attribute: 'style', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
3766
4449
|
case 'pp-mob-css':
|
|
@@ -4020,7 +4703,25 @@ function applyChangesetEntry(entry, iframeDoc) {
|
|
|
4020
4703
|
case 'attribute':
|
|
4021
4704
|
if (entry.attribute && entry.value != null) {
|
|
4022
4705
|
if (String(entry.attribute).toLowerCase() === 'style') break;
|
|
4023
|
-
|
|
4706
|
+
if (
|
|
4707
|
+
String(entry.attribute).toLowerCase() === 'src' &&
|
|
4708
|
+
el.tagName &&
|
|
4709
|
+
el.tagName.toLowerCase() === 'video'
|
|
4710
|
+
) {
|
|
4711
|
+
setVideoSrc(el, entry.value);
|
|
4712
|
+
} else if (
|
|
4713
|
+
String(entry.attribute).toLowerCase() === 'data-youtube-id' &&
|
|
4714
|
+
isYoutubeVideoElement(el)
|
|
4715
|
+
) {
|
|
4716
|
+
setYoutubeVideoId(el, entry.value);
|
|
4717
|
+
} else if (
|
|
4718
|
+
String(entry.attribute).toLowerCase() === 'data-vimeo-id' &&
|
|
4719
|
+
isVimeoVideoElement(el)
|
|
4720
|
+
) {
|
|
4721
|
+
setVimeoVideoId(el, entry.value);
|
|
4722
|
+
} else {
|
|
4723
|
+
el.setAttribute(entry.attribute, entry.value);
|
|
4724
|
+
}
|
|
4024
4725
|
}
|
|
4025
4726
|
break;
|
|
4026
4727
|
case 'insert': {
|
|
@@ -4029,9 +4730,12 @@ function applyChangesetEntry(entry, iframeDoc) {
|
|
|
4029
4730
|
if (structuralDedupeKey) appliedStructuralChangesetKeys[structuralDedupeKey] = true;
|
|
4030
4731
|
break;
|
|
4031
4732
|
}
|
|
4032
|
-
case 'remove':
|
|
4733
|
+
case 'remove': {
|
|
4734
|
+
var inst = el.getAttribute && el.getAttribute('data-vve-instance');
|
|
4735
|
+
if (inst && String(entry.selector || '').indexOf('data-vve-instance') < 0) break;
|
|
4033
4736
|
el.style.display = 'none';
|
|
4034
4737
|
break;
|
|
4738
|
+
}
|
|
4035
4739
|
case 'reorder': {
|
|
4036
4740
|
var target = entry.targetSelector ? querySelectorResolved(iframeDoc, entry.targetSelector) : null;
|
|
4037
4741
|
if (!target || !el.parentNode || !target.parentNode) break;
|
|
@@ -4251,7 +4955,11 @@ function deselectElement(options) {
|
|
|
4251
4955
|
document.getElementById('rp-accordion').style.display = 'none';
|
|
4252
4956
|
document.getElementById('bc-path').textContent = 'No element selected';
|
|
4253
4957
|
document.getElementById('bc-path').style.color = 'var(--text-3)';
|
|
4254
|
-
|
|
4958
|
+
var preserveMainTab =
|
|
4959
|
+
!!(options && options.preserveMainTab) ||
|
|
4960
|
+
currentMainTab === 'history' ||
|
|
4961
|
+
currentMainTab === 'states';
|
|
4962
|
+
if (!preserveMainTab) switchMainTab('design');
|
|
4255
4963
|
if (!skipToolbarUpdate) updateSelectionToolbar();
|
|
4256
4964
|
syncDomTreeSelection();
|
|
4257
4965
|
} finally {
|
|
@@ -4338,6 +5046,30 @@ function setDragHandleActive(on) {
|
|
|
4338
5046
|
}
|
|
4339
5047
|
}
|
|
4340
5048
|
|
|
5049
|
+
function getIframeElementVisualRect(el) {
|
|
5050
|
+
var iframe = document.getElementById('iframeId');
|
|
5051
|
+
if (!el || !iframe) return null;
|
|
5052
|
+
// Element rects from the iframe document are in iframe viewport space, not the shell viewport.
|
|
5053
|
+
var elR = el.getBoundingClientRect();
|
|
5054
|
+
var iframeR = iframe.getBoundingClientRect();
|
|
5055
|
+
var cw = iframe.clientWidth || iframe.offsetWidth || 1;
|
|
5056
|
+
var ch = iframe.clientHeight || iframe.offsetHeight || 1;
|
|
5057
|
+
var scaleX = iframeR.width / cw;
|
|
5058
|
+
var scaleY = iframeR.height / ch;
|
|
5059
|
+
var top = iframeR.top + elR.top * scaleY;
|
|
5060
|
+
var left = iframeR.left + elR.left * scaleX;
|
|
5061
|
+
var width = elR.width * scaleX;
|
|
5062
|
+
var height = elR.height * scaleY;
|
|
5063
|
+
return {
|
|
5064
|
+
left: left,
|
|
5065
|
+
top: top,
|
|
5066
|
+
width: width,
|
|
5067
|
+
height: height,
|
|
5068
|
+
right: left + width,
|
|
5069
|
+
bottom: top + height,
|
|
5070
|
+
};
|
|
5071
|
+
}
|
|
5072
|
+
|
|
4341
5073
|
function positionSelectionToolbar() {
|
|
4342
5074
|
var bar = document.getElementById('selection-floater');
|
|
4343
5075
|
var iframe = document.getElementById('iframeId');
|
|
@@ -4349,16 +5081,20 @@ function positionSelectionToolbar() {
|
|
|
4349
5081
|
renderRightPanel(liveSelected);
|
|
4350
5082
|
syncDomTreeSelection();
|
|
4351
5083
|
}
|
|
4352
|
-
var elR = selectedEl
|
|
4353
|
-
|
|
5084
|
+
var elR = getIframeElementVisualRect(selectedEl);
|
|
5085
|
+
if (!elR) return;
|
|
4354
5086
|
var panelR = panel.getBoundingClientRect();
|
|
4355
|
-
var
|
|
4356
|
-
var
|
|
4357
|
-
|
|
4358
|
-
var
|
|
4359
|
-
|
|
5087
|
+
var panelScrollLeft = panel.scrollLeft || 0;
|
|
5088
|
+
var panelScrollTop = panel.scrollTop || 0;
|
|
5089
|
+
var left = elR.left - panelR.left + panelScrollLeft + elR.width / 2 - bar.offsetWidth / 2;
|
|
5090
|
+
var top = elR.top - panelR.top + panelScrollTop - bar.offsetHeight - 8;
|
|
5091
|
+
if (top < panelScrollTop + 6) top = elR.bottom - panelR.top + panelScrollTop + 8;
|
|
5092
|
+
var minL = panelScrollLeft + 6;
|
|
5093
|
+
var maxL = panelScrollLeft + Math.max(6, panel.clientWidth - bar.offsetWidth - 8);
|
|
5094
|
+
left = Math.max(minL, Math.min(left, maxL));
|
|
4360
5095
|
bar.style.left = Math.round(left) + 'px';
|
|
4361
5096
|
bar.style.top = Math.round(top) + 'px';
|
|
5097
|
+
syncMoveFloaterButtons(selectedEl);
|
|
4362
5098
|
}
|
|
4363
5099
|
|
|
4364
5100
|
function updateSelectionToolbar() {
|
|
@@ -4376,6 +5112,7 @@ function updateSelectionToolbar() {
|
|
|
4376
5112
|
if (selectedEl !== liveSelected) selectedEl = liveSelected;
|
|
4377
5113
|
selectedElFingerprint = buildSelector(liveSelected);
|
|
4378
5114
|
bar.style.display = 'flex';
|
|
5115
|
+
syncMoveFloaterButtons(liveSelected);
|
|
4379
5116
|
requestAnimationFrame(function() { positionSelectionToolbar(); });
|
|
4380
5117
|
}
|
|
4381
5118
|
|
|
@@ -4392,6 +5129,11 @@ function bindSelectionToolbarScroll() {
|
|
|
4392
5129
|
}
|
|
4393
5130
|
selectionScrollWin = w;
|
|
4394
5131
|
w.addEventListener('scroll', onFloaterScroll, true);
|
|
5132
|
+
var panel = document.getElementById('iframe-panel');
|
|
5133
|
+
if (panel && !selectionPanelScrollBound) {
|
|
5134
|
+
selectionPanelScrollBound = true;
|
|
5135
|
+
panel.addEventListener('scroll', onFloaterScroll, { passive: true });
|
|
5136
|
+
}
|
|
4395
5137
|
if (!selectionResizeBound) {
|
|
4396
5138
|
selectionResizeBound = true;
|
|
4397
5139
|
window.addEventListener('resize', onFloaterScroll);
|
|
@@ -4413,7 +5155,6 @@ function scrollIframeElementIntoView(el) {
|
|
|
4413
5155
|
function selectElementFromTree(el) {
|
|
4414
5156
|
selectElement(el);
|
|
4415
5157
|
scrollIframeElementIntoView(el);
|
|
4416
|
-
if (currentMainTab !== 'design') switchMainTab('design');
|
|
4417
5158
|
}
|
|
4418
5159
|
|
|
4419
5160
|
function duplicateSelectedEl() {
|
|
@@ -4486,12 +5227,26 @@ function toggleHideSelectedEl() {
|
|
|
4486
5227
|
|
|
4487
5228
|
function deleteSelectedEl() {
|
|
4488
5229
|
if (!selectedEl || !selectedEl.parentNode) return;
|
|
5230
|
+
var inst = selectedEl.getAttribute && selectedEl.getAttribute('data-vve-instance');
|
|
5231
|
+
if (inst && activeVarId && removeEditorInsertByInstanceId(inst)) {
|
|
5232
|
+
saveCurrentVariationHtml();
|
|
5233
|
+
recomputeEditorDirty();
|
|
5234
|
+
deselectElement();
|
|
5235
|
+
scheduleDomTreeRefresh();
|
|
5236
|
+
if (currentMainTab === 'history') renderHistoryTab();
|
|
5237
|
+
return;
|
|
5238
|
+
}
|
|
4489
5239
|
var delSel = buildSelector(selectedEl);
|
|
5240
|
+
var cancelledInsert =
|
|
5241
|
+
activeVarId && cancelSessionInsertForElement(activeVarId, selectedEl);
|
|
4490
5242
|
selectedEl.remove();
|
|
4491
|
-
if (activeVarId) {
|
|
5243
|
+
if (activeVarId && !cancelledInsert) {
|
|
4492
5244
|
var delRow = { selector: delSel, type: 'remove' };
|
|
4493
5245
|
appendSessionStructuralChainRow(activeVarId, delRow);
|
|
4494
5246
|
logStructuralStateChange(delRow, 'Deleted via toolbar', 'Element removed', null);
|
|
5247
|
+
} else if (cancelledInsert) {
|
|
5248
|
+
commitStateChangesForActiveVariation();
|
|
5249
|
+
if (currentMainTab === 'history') renderHistoryTab();
|
|
4495
5250
|
}
|
|
4496
5251
|
saveCurrentVariationHtml();
|
|
4497
5252
|
recomputeEditorDirty();
|
|
@@ -4518,14 +5273,13 @@ function syncDomTreeSelection() {
|
|
|
4518
5273
|
}
|
|
4519
5274
|
|
|
4520
5275
|
function scheduleDomTreeRefresh() {
|
|
4521
|
-
if (currentLeftTab !== 'elements' && currentLeftTab !== 'dom-tree') return;
|
|
4522
5276
|
if (domTreeRefreshTimer) clearTimeout(domTreeRefreshTimer);
|
|
4523
5277
|
domTreeRefreshTimer = setTimeout(function() {
|
|
4524
5278
|
domTreeRefreshTimer = null;
|
|
4525
5279
|
var inp = document.getElementById('comp-search');
|
|
4526
5280
|
var q = inp ? inp.value : '';
|
|
4527
|
-
|
|
4528
|
-
|
|
5281
|
+
renderElementsTree(q);
|
|
5282
|
+
if (currentLeftTab === 'dom-tree') renderDomTree(q);
|
|
4529
5283
|
}, 150);
|
|
4530
5284
|
}
|
|
4531
5285
|
|
|
@@ -4548,6 +5302,162 @@ function domTreePathSegment(el) {
|
|
|
4548
5302
|
return tag + '[' + idx + ']';
|
|
4549
5303
|
}
|
|
4550
5304
|
|
|
5305
|
+
function instanceIdFromInsertHtml(html) {
|
|
5306
|
+
var m = String(html || '').match(/data-vve-instance=["']([^"']+)["']/);
|
|
5307
|
+
return m ? m[1] : '';
|
|
5308
|
+
}
|
|
5309
|
+
|
|
5310
|
+
function resolveInsertedElementFromEntry(doc, entry) {
|
|
5311
|
+
if (!doc || !entry) return null;
|
|
5312
|
+
var instId = instanceIdFromInsertHtml(entry.html);
|
|
5313
|
+
if (!instId) return null;
|
|
5314
|
+
try {
|
|
5315
|
+
var safe = String(instId).split('"').join('\\"');
|
|
5316
|
+
return doc.querySelector('[data-vve-instance="' + safe + '"]');
|
|
5317
|
+
} catch(_) {
|
|
5318
|
+
return null;
|
|
5319
|
+
}
|
|
5320
|
+
}
|
|
5321
|
+
|
|
5322
|
+
function removeInsertFromDomByEntry(entry, iframeDoc) {
|
|
5323
|
+
if (!entry || !iframeDoc) return false;
|
|
5324
|
+
var insertedEl = resolveInsertedElementFromEntry(iframeDoc, entry);
|
|
5325
|
+
if (!insertedEl || !insertedEl.parentNode) return false;
|
|
5326
|
+
if (
|
|
5327
|
+
selectedEl &&
|
|
5328
|
+
(selectedEl === insertedEl || (insertedEl.contains && insertedEl.contains(selectedEl)))
|
|
5329
|
+
) {
|
|
5330
|
+
deselectElement();
|
|
5331
|
+
}
|
|
5332
|
+
insertedEl.remove();
|
|
5333
|
+
return true;
|
|
5334
|
+
}
|
|
5335
|
+
|
|
5336
|
+
/** Remove an editor insert everywhere (DOM + session + saved changesets + live history), keyed by data-vve-instance. */
|
|
5337
|
+
function removeEditorInsertByInstanceId(instId, opts) {
|
|
5338
|
+
if (!instId || !String(instId).trim()) return false;
|
|
5339
|
+
opts = opts || {};
|
|
5340
|
+
var varId = opts.varId || activeVarId;
|
|
5341
|
+
if (!varId) return false;
|
|
5342
|
+
var needle = 'data-vve-instance="' + String(instId).split('"').join('\\"') + '"';
|
|
5343
|
+
var didWork = false;
|
|
5344
|
+
|
|
5345
|
+
if (!opts.skipDom) {
|
|
5346
|
+
var iframeDoc = document.getElementById('iframeId').contentDocument;
|
|
5347
|
+
if (iframeDoc) {
|
|
5348
|
+
try {
|
|
5349
|
+
var safe = String(instId).split('"').join('\\"');
|
|
5350
|
+
var el = iframeDoc.querySelector('[data-vve-instance="' + safe + '"]');
|
|
5351
|
+
if (el && el.parentNode) {
|
|
5352
|
+
if (
|
|
5353
|
+
selectedEl &&
|
|
5354
|
+
(selectedEl === el || (el.contains && el.contains(selectedEl)))
|
|
5355
|
+
) {
|
|
5356
|
+
deselectElement();
|
|
5357
|
+
}
|
|
5358
|
+
el.remove();
|
|
5359
|
+
didWork = true;
|
|
5360
|
+
}
|
|
5361
|
+
} catch(_) {}
|
|
5362
|
+
}
|
|
5363
|
+
}
|
|
5364
|
+
|
|
5365
|
+
var sessionArr = sessionStructuralChainRowsByVarId[varId];
|
|
5366
|
+
if (sessionArr && sessionArr.length) {
|
|
5367
|
+
for (var i = sessionArr.length - 1; i >= 0; i--) {
|
|
5368
|
+
var row = sessionArr[i];
|
|
5369
|
+
if (!row || normalizeChangesetType(row) !== 'insert' || !row.html) continue;
|
|
5370
|
+
if (String(row.html).indexOf(needle) < 0) continue;
|
|
5371
|
+
var ts = row.vveTs;
|
|
5372
|
+
try {
|
|
5373
|
+
var k = structuralChangesetDedupKey(row);
|
|
5374
|
+
if (k) delete appliedStructuralChangesetKeys[k];
|
|
5375
|
+
} catch(_) {}
|
|
5376
|
+
sessionArr.splice(i, 1);
|
|
5377
|
+
removeStructuralStateChangeByTimestamp(varId, ts);
|
|
5378
|
+
didWork = true;
|
|
5379
|
+
}
|
|
5380
|
+
}
|
|
5381
|
+
|
|
5382
|
+
var v = variations.find(function(x) { return x._id === varId; });
|
|
5383
|
+
if (v) {
|
|
5384
|
+
var saved = parseVariationChangesets(v);
|
|
5385
|
+
var savedChanged = false;
|
|
5386
|
+
for (var si = saved.length - 1; si >= 0; si--) {
|
|
5387
|
+
var entry = saved[si];
|
|
5388
|
+
if (!entry || normalizeChangesetType(entry) !== 'insert' || !entry.html) continue;
|
|
5389
|
+
if (String(entry.html).indexOf(needle) < 0) continue;
|
|
5390
|
+
try {
|
|
5391
|
+
delete appliedChangesetSnapshots[entrySnapshotKey(entry)];
|
|
5392
|
+
} catch(_) {}
|
|
5393
|
+
saved.splice(si, 1);
|
|
5394
|
+
savedChanged = true;
|
|
5395
|
+
didWork = true;
|
|
5396
|
+
}
|
|
5397
|
+
if (savedChanged && varId === activeVarId) persistActiveVariationChangesets(saved);
|
|
5398
|
+
}
|
|
5399
|
+
|
|
5400
|
+
for (var j = stateChanges.length - 1; j >= 0; j--) {
|
|
5401
|
+
var c = stateChanges[j];
|
|
5402
|
+
if (!c || !c.isStructuralLive) continue;
|
|
5403
|
+
if (normalizeChangesetType({ type: c.structuralType }) !== 'insert') continue;
|
|
5404
|
+
var match = false;
|
|
5405
|
+
try {
|
|
5406
|
+
if (c.targetEl && c.targetEl.getAttribute && c.targetEl.getAttribute('data-vve-instance') === instId) {
|
|
5407
|
+
match = true;
|
|
5408
|
+
}
|
|
5409
|
+
} catch(_) {}
|
|
5410
|
+
if (match) {
|
|
5411
|
+
stateChanges.splice(j, 1);
|
|
5412
|
+
didWork = true;
|
|
5413
|
+
}
|
|
5414
|
+
}
|
|
5415
|
+
|
|
5416
|
+
return didWork;
|
|
5417
|
+
}
|
|
5418
|
+
|
|
5419
|
+
/** Live DOM nodes inserted via the visual editor, ordered by changeset/session insert order. */
|
|
5420
|
+
function collectEditorInsertedElements(doc) {
|
|
5421
|
+
if (!doc || !doc.body) return [];
|
|
5422
|
+
var byInst = {};
|
|
5423
|
+
var els;
|
|
5424
|
+
try {
|
|
5425
|
+
els = doc.querySelectorAll('[data-vve-instance]');
|
|
5426
|
+
} catch(_) {
|
|
5427
|
+
els = [];
|
|
5428
|
+
}
|
|
5429
|
+
for (var i = 0; i < els.length; i++) {
|
|
5430
|
+
var el = els[i];
|
|
5431
|
+
if (!el || el.nodeType !== 1) continue;
|
|
5432
|
+
var inst = el.getAttribute('data-vve-instance');
|
|
5433
|
+
if (inst && String(inst).trim()) byInst[String(inst)] = el;
|
|
5434
|
+
}
|
|
5435
|
+
|
|
5436
|
+
var ordered = [];
|
|
5437
|
+
var seen = {};
|
|
5438
|
+
function addEl(el) {
|
|
5439
|
+
if (!el || !el.isConnected) return;
|
|
5440
|
+
var k = el.getAttribute && el.getAttribute('data-vve-instance');
|
|
5441
|
+
if (!k || seen[k]) return;
|
|
5442
|
+
seen[k] = true;
|
|
5443
|
+
ordered.push(el);
|
|
5444
|
+
}
|
|
5445
|
+
|
|
5446
|
+
if (activeVarId) {
|
|
5447
|
+
var variation = variations.find(function(v) { return v._id === activeVarId; });
|
|
5448
|
+
if (variation) {
|
|
5449
|
+
var cs = buildPersistedChainSetsForVariation(variation);
|
|
5450
|
+
for (var j = 0; j < cs.length; j++) {
|
|
5451
|
+
var row = cs[j];
|
|
5452
|
+
if (normalizeChangesetType(row) !== 'insert') continue;
|
|
5453
|
+
var instId = instanceIdFromInsertHtml(row.html);
|
|
5454
|
+
if (instId && byInst[instId]) addEl(byInst[instId]);
|
|
5455
|
+
}
|
|
5456
|
+
}
|
|
5457
|
+
}
|
|
5458
|
+
return ordered;
|
|
5459
|
+
}
|
|
5460
|
+
|
|
4551
5461
|
function renderElementsTree(filterRaw) {
|
|
4552
5462
|
var filterText = (filterRaw || '').toLowerCase().trim();
|
|
4553
5463
|
var root = document.getElementById('elements-root');
|
|
@@ -4555,14 +5465,10 @@ function renderElementsTree(filterRaw) {
|
|
|
4555
5465
|
var iframe = document.getElementById('iframeId');
|
|
4556
5466
|
var doc = iframe && iframe.contentDocument;
|
|
4557
5467
|
if (!isIframeDomReady(iframe, doc)) {
|
|
4558
|
-
root.innerHTML = '<div class="dt-muted">Load a page to see
|
|
5468
|
+
root.innerHTML = '<div class="dt-muted">Load a page to see added elements.</div>';
|
|
4559
5469
|
return;
|
|
4560
5470
|
}
|
|
4561
5471
|
|
|
4562
|
-
function skippable(el) {
|
|
4563
|
-
return isDomTreeSkippableTagName(el.tagName);
|
|
4564
|
-
}
|
|
4565
|
-
|
|
4566
5472
|
function nodeIcon(tag) {
|
|
4567
5473
|
tag = (tag || '').toLowerCase();
|
|
4568
5474
|
if (/^h[1-6]$/.test(tag)) return 'bi bi-type-h1';
|
|
@@ -4582,50 +5488,10 @@ function renderElementsTree(filterRaw) {
|
|
|
4582
5488
|
return tag.toUpperCase();
|
|
4583
5489
|
}
|
|
4584
5490
|
|
|
4585
|
-
|
|
4586
|
-
if (!el || el.nodeType !== 1) return false;
|
|
4587
|
-
if (skippable(el)) return false;
|
|
4588
|
-
var tag = (el.tagName || '').toLowerCase();
|
|
4589
|
-
if (tag !== 'svg') {
|
|
4590
|
-
var p = el.parentElement;
|
|
4591
|
-
while (p) {
|
|
4592
|
-
if ((p.tagName || '').toLowerCase() === 'svg') return false;
|
|
4593
|
-
p = p.parentElement;
|
|
4594
|
-
}
|
|
4595
|
-
}
|
|
4596
|
-
return true;
|
|
4597
|
-
}
|
|
4598
|
-
|
|
4599
|
-
var nodes = [];
|
|
4600
|
-
var i, cursor;
|
|
4601
|
-
try {
|
|
4602
|
-
cursor = doc.createTreeWalker(doc.body, NodeFilter.SHOW_ELEMENT, null);
|
|
4603
|
-
} catch(_) {
|
|
4604
|
-
cursor = null;
|
|
4605
|
-
}
|
|
4606
|
-
if (cursor) {
|
|
4607
|
-
while (cursor.nextNode()) {
|
|
4608
|
-
var node = cursor.currentNode;
|
|
4609
|
-
if (isListableNode(node)) nodes.push(node);
|
|
4610
|
-
if (nodes.length > 4000) break;
|
|
4611
|
-
}
|
|
4612
|
-
} else {
|
|
4613
|
-
function collectFlat(el) {
|
|
4614
|
-
if (!el || !el.children) return;
|
|
4615
|
-
for (var j = 0; j < el.children.length; j++) {
|
|
4616
|
-
var c = el.children[j];
|
|
4617
|
-
if (!isListableNode(c)) continue;
|
|
4618
|
-
nodes.push(c);
|
|
4619
|
-
if (nodes.length > 4000) return;
|
|
4620
|
-
collectFlat(c);
|
|
4621
|
-
if (nodes.length > 4000) return;
|
|
4622
|
-
}
|
|
4623
|
-
}
|
|
4624
|
-
collectFlat(doc.body);
|
|
4625
|
-
}
|
|
5491
|
+
var nodes = collectEditorInsertedElements(doc);
|
|
4626
5492
|
|
|
4627
5493
|
root.innerHTML = '';
|
|
4628
|
-
for (i = 0; i < nodes.length; i++) {
|
|
5494
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
4629
5495
|
var el = nodes[i];
|
|
4630
5496
|
var lblText = labelFor(el);
|
|
4631
5497
|
if (filterText && lblText.toLowerCase().indexOf(filterText) < 0) continue;
|
|
@@ -4663,14 +5529,39 @@ function renderElementsTree(filterRaw) {
|
|
|
4663
5529
|
|
|
4664
5530
|
if (!root.querySelector('.dt-row')) {
|
|
4665
5531
|
root.innerHTML = filterText
|
|
4666
|
-
? '<div class="dt-muted">No elements match your search.</div>'
|
|
4667
|
-
: '<div class="dt-muted">No elements
|
|
5532
|
+
? '<div class="dt-muted">No added elements match your search.</div>'
|
|
5533
|
+
: '<div class="dt-muted">No elements added yet. Use Components or Sections to insert.</div>';
|
|
4668
5534
|
}
|
|
4669
5535
|
root.onmouseleave = function() {
|
|
4670
5536
|
clearTreeHoverHighlight();
|
|
4671
5537
|
};
|
|
4672
5538
|
}
|
|
4673
5539
|
|
|
5540
|
+
function domTreeLabelSuffix(el) {
|
|
5541
|
+
if (el.id != null && el.id !== '') return '#' + String(el.id).slice(0, 40);
|
|
5542
|
+
var cn = el.className && typeof el.className === 'string' ? el.className.trim() : '';
|
|
5543
|
+
if (cn) {
|
|
5544
|
+
var parts = cn.split(/s+/).filter(function(x) { return x.indexOf('vve-') !== 0; }).slice(0, 2).join('.');
|
|
5545
|
+
if (parts) return '.' + parts.slice(0, 56);
|
|
5546
|
+
}
|
|
5547
|
+
return '';
|
|
5548
|
+
}
|
|
5549
|
+
|
|
5550
|
+
function domTreeLabelFor(el) {
|
|
5551
|
+
return (el.tagName || '').toLowerCase() + domTreeLabelSuffix(el);
|
|
5552
|
+
}
|
|
5553
|
+
|
|
5554
|
+
function setDomTreeLabelContent(lbl, el) {
|
|
5555
|
+
var tag = (el.tagName || '').toLowerCase();
|
|
5556
|
+
lbl.textContent = '';
|
|
5557
|
+
var tagSpan = document.createElement('span');
|
|
5558
|
+
tagSpan.className = 'dt-tag';
|
|
5559
|
+
tagSpan.textContent = tag;
|
|
5560
|
+
lbl.appendChild(tagSpan);
|
|
5561
|
+
var suffix = domTreeLabelSuffix(el);
|
|
5562
|
+
if (suffix) lbl.appendChild(document.createTextNode(suffix));
|
|
5563
|
+
}
|
|
5564
|
+
|
|
4674
5565
|
function renderDomTree(filterRaw) {
|
|
4675
5566
|
var filterText = (filterRaw || '').toLowerCase().trim();
|
|
4676
5567
|
var root = document.getElementById('dom-tree-root');
|
|
@@ -4688,14 +5579,7 @@ function renderDomTree(filterRaw) {
|
|
|
4688
5579
|
}
|
|
4689
5580
|
|
|
4690
5581
|
function labelFor(el) {
|
|
4691
|
-
|
|
4692
|
-
if (el.id != null && el.id !== '') return tag + '#' + String(el.id).slice(0, 40);
|
|
4693
|
-
var cn = el.className && typeof el.className === 'string' ? el.className.trim() : '';
|
|
4694
|
-
if (cn) {
|
|
4695
|
-
var parts = cn.split(/s+/).filter(function(x) { return x.indexOf('vve-') !== 0; }).slice(0, 2).join('.');
|
|
4696
|
-
if (parts) return tag + '.' + parts.slice(0, 56);
|
|
4697
|
-
}
|
|
4698
|
-
return tag;
|
|
5582
|
+
return domTreeLabelFor(el);
|
|
4699
5583
|
}
|
|
4700
5584
|
|
|
4701
5585
|
function skippable(el) {
|
|
@@ -4772,7 +5656,7 @@ function renderDomTree(filterRaw) {
|
|
|
4772
5656
|
|
|
4773
5657
|
var lbl = document.createElement('div');
|
|
4774
5658
|
lbl.className = 'dt-lbl';
|
|
4775
|
-
lbl
|
|
5659
|
+
setDomTreeLabelContent(lbl, el);
|
|
4776
5660
|
lbl.title = buildSelector(el);
|
|
4777
5661
|
|
|
4778
5662
|
row.appendChild(chev);
|
|
@@ -4823,6 +5707,189 @@ function pr2(l1, i1, l2, i2) {
|
|
|
4823
5707
|
'<div class="pr2-item"><div class="pr2-lbl">'+l2+'</div>'+i2+'</div></div>';
|
|
4824
5708
|
}
|
|
4825
5709
|
function subLbl(text) { return '<div class="sub-lbl">'+text+'</div>'; }
|
|
5710
|
+
|
|
5711
|
+
function isLinkElement(el) {
|
|
5712
|
+
if (!el || el.nodeType !== 1) return false;
|
|
5713
|
+
var tag = (el.tagName || '').toLowerCase();
|
|
5714
|
+
if (tag === 'a') return true;
|
|
5715
|
+
try {
|
|
5716
|
+
return el.getAttribute && el.getAttribute('role') === 'link';
|
|
5717
|
+
} catch(_) {}
|
|
5718
|
+
return false;
|
|
5719
|
+
}
|
|
5720
|
+
|
|
5721
|
+
function isFormControlElement(el) {
|
|
5722
|
+
if (!el || el.nodeType !== 1) return false;
|
|
5723
|
+
var tag = (el.tagName || '').toLowerCase();
|
|
5724
|
+
return tag === 'input' || tag === 'textarea' || tag === 'select';
|
|
5725
|
+
}
|
|
5726
|
+
|
|
5727
|
+
function getFormControlValue(el) {
|
|
5728
|
+
if (!isFormControlElement(el)) return '';
|
|
5729
|
+
try {
|
|
5730
|
+
return el.value != null ? String(el.value) : '';
|
|
5731
|
+
} catch(_) {
|
|
5732
|
+
return '';
|
|
5733
|
+
}
|
|
5734
|
+
}
|
|
5735
|
+
|
|
5736
|
+
function getVideoSrc(el) {
|
|
5737
|
+
if (!el || el.nodeType !== 1) return '';
|
|
5738
|
+
try {
|
|
5739
|
+
var source = el.querySelector && el.querySelector('source');
|
|
5740
|
+
if (source && source.getAttribute('src')) return source.getAttribute('src') || '';
|
|
5741
|
+
return el.getAttribute('src') || '';
|
|
5742
|
+
} catch(_) {
|
|
5743
|
+
return '';
|
|
5744
|
+
}
|
|
5745
|
+
}
|
|
5746
|
+
|
|
5747
|
+
function setVideoSrc(el, value) {
|
|
5748
|
+
if (!el || el.nodeType !== 1) return;
|
|
5749
|
+
var v = value == null ? '' : String(value);
|
|
5750
|
+
try {
|
|
5751
|
+
var source = el.querySelector && el.querySelector('source');
|
|
5752
|
+
if (source) {
|
|
5753
|
+
if (v) source.setAttribute('src', v);
|
|
5754
|
+
else source.removeAttribute('src');
|
|
5755
|
+
} else if (v) {
|
|
5756
|
+
el.setAttribute('src', v);
|
|
5757
|
+
} else {
|
|
5758
|
+
el.removeAttribute('src');
|
|
5759
|
+
}
|
|
5760
|
+
try {
|
|
5761
|
+
el.load();
|
|
5762
|
+
} catch(_) {}
|
|
5763
|
+
} catch(_) {}
|
|
5764
|
+
}
|
|
5765
|
+
|
|
5766
|
+
function isYoutubeVideoElement(el) {
|
|
5767
|
+
if (!el || el.nodeType !== 1) return false;
|
|
5768
|
+
if ((el.tagName || '').toLowerCase() !== 'iframe') return false;
|
|
5769
|
+
if (el.hasAttribute && el.hasAttribute('data-youtube-id')) return true;
|
|
5770
|
+
var src = el.getAttribute('src') || '';
|
|
5771
|
+
return src.indexOf('youtube.com/embed/') !== -1 || src.indexOf('youtu.be/') !== -1;
|
|
5772
|
+
}
|
|
5773
|
+
|
|
5774
|
+
function normalizeYoutubeVideoId(input) {
|
|
5775
|
+
var raw = String(input || '').trim();
|
|
5776
|
+
if (!raw) return '';
|
|
5777
|
+
var m = raw.match(new RegExp('(?:youtube\\.com/(?:embed/|watch\\?(?:.*&)?v=|shorts/|live/)|youtu\\.be/)([A-Za-z0-9_-]{11})', 'i'));
|
|
5778
|
+
if (m) return m[1];
|
|
5779
|
+
var bare = raw.match(/^([A-Za-z0-9_-]{11})$/);
|
|
5780
|
+
return bare ? bare[1] : raw;
|
|
5781
|
+
}
|
|
5782
|
+
|
|
5783
|
+
function getYoutubeVideoId(el) {
|
|
5784
|
+
if (!isYoutubeVideoElement(el)) return '';
|
|
5785
|
+
try {
|
|
5786
|
+
var explicit = el.getAttribute('data-youtube-id');
|
|
5787
|
+
if (explicit != null && String(explicit).trim()) return String(explicit).trim();
|
|
5788
|
+
var src = el.getAttribute('src') || '';
|
|
5789
|
+
var m = src.match(new RegExp('(?:youtube\\.com/embed/|youtu\\.be/)([A-Za-z0-9_-]{11})', 'i'));
|
|
5790
|
+
return m ? m[1] : '';
|
|
5791
|
+
} catch(_) {
|
|
5792
|
+
return '';
|
|
5793
|
+
}
|
|
5794
|
+
}
|
|
5795
|
+
|
|
5796
|
+
function setYoutubeVideoId(el, value) {
|
|
5797
|
+
if (!el || el.nodeType !== 1) return;
|
|
5798
|
+
var id = normalizeYoutubeVideoId(value);
|
|
5799
|
+
try {
|
|
5800
|
+
if (id) {
|
|
5801
|
+
el.setAttribute('data-youtube-id', id);
|
|
5802
|
+
el.setAttribute('src', 'https://www.youtube.com/embed/' + id);
|
|
5803
|
+
} else {
|
|
5804
|
+
el.removeAttribute('data-youtube-id');
|
|
5805
|
+
el.setAttribute('src', 'about:blank');
|
|
5806
|
+
}
|
|
5807
|
+
} catch(_) {}
|
|
5808
|
+
}
|
|
5809
|
+
|
|
5810
|
+
function isVimeoVideoElement(el) {
|
|
5811
|
+
if (!el || el.nodeType !== 1) return false;
|
|
5812
|
+
if ((el.tagName || '').toLowerCase() !== 'iframe') return false;
|
|
5813
|
+
if (el.hasAttribute && el.hasAttribute('data-vimeo-id')) return true;
|
|
5814
|
+
var src = el.getAttribute('src') || '';
|
|
5815
|
+
return src.indexOf('player.vimeo.com/video/') !== -1 || src.indexOf('vimeo.com/video/') !== -1;
|
|
5816
|
+
}
|
|
5817
|
+
|
|
5818
|
+
function isEmbeddedVideoIframe(el) {
|
|
5819
|
+
return isYoutubeVideoElement(el) || isVimeoVideoElement(el);
|
|
5820
|
+
}
|
|
5821
|
+
|
|
5822
|
+
function normalizeVimeoVideoId(input) {
|
|
5823
|
+
var raw = String(input || '').trim();
|
|
5824
|
+
if (!raw) return '';
|
|
5825
|
+
var m = raw.match(new RegExp('(?:player\\.vimeo\\.com/video/|vimeo\\.com/(?:video/)?)([0-9]+)', 'i'));
|
|
5826
|
+
if (m) return m[1];
|
|
5827
|
+
var bare = raw.match(/^([0-9]+)$/);
|
|
5828
|
+
return bare ? bare[1] : raw.replace(/[^d]/g, '');
|
|
5829
|
+
}
|
|
5830
|
+
|
|
5831
|
+
function getVimeoVideoId(el) {
|
|
5832
|
+
if (!isVimeoVideoElement(el)) return '';
|
|
5833
|
+
try {
|
|
5834
|
+
var explicit = el.getAttribute('data-vimeo-id');
|
|
5835
|
+
if (explicit != null && String(explicit).trim()) return String(explicit).trim();
|
|
5836
|
+
var src = el.getAttribute('src') || '';
|
|
5837
|
+
var m = src.match(new RegExp('(?:player\\.vimeo\\.com/video/|vimeo\\.com/video/)([0-9]+)', 'i'));
|
|
5838
|
+
return m ? m[1] : '';
|
|
5839
|
+
} catch(_) {
|
|
5840
|
+
return '';
|
|
5841
|
+
}
|
|
5842
|
+
}
|
|
5843
|
+
|
|
5844
|
+
function setVimeoVideoId(el, value) {
|
|
5845
|
+
if (!el || el.nodeType !== 1) return;
|
|
5846
|
+
var id = normalizeVimeoVideoId(value);
|
|
5847
|
+
try {
|
|
5848
|
+
if (id) {
|
|
5849
|
+
el.setAttribute('data-vimeo-id', id);
|
|
5850
|
+
el.setAttribute('src', 'https://player.vimeo.com/video/' + id);
|
|
5851
|
+
} else {
|
|
5852
|
+
el.removeAttribute('data-vimeo-id');
|
|
5853
|
+
el.setAttribute('src', 'about:blank');
|
|
5854
|
+
}
|
|
5855
|
+
} catch(_) {}
|
|
5856
|
+
}
|
|
5857
|
+
|
|
5858
|
+
function buildAnchorContentFieldsHtml(el) {
|
|
5859
|
+
return (
|
|
5860
|
+
subLbl('Link attributes') +
|
|
5861
|
+
pr('Href', '<input class="pr-inp" id="pp-href" type="text" value="'+esc(el.getAttribute('href')||'')+'" placeholder="https:// or #section">') +
|
|
5862
|
+
pr2(
|
|
5863
|
+
'Target',
|
|
5864
|
+
'<select class="pr-inp" id="pp-target">'+selOpts(['','_self','_blank','_parent','_top'],el.getAttribute('target')||'')+'</select>',
|
|
5865
|
+
'Rel',
|
|
5866
|
+
'<input class="pr-inp" id="pp-rel" type="text" value="'+esc(el.getAttribute('rel')||'')+'" placeholder="noopener noreferrer">'
|
|
5867
|
+
) +
|
|
5868
|
+
pr2(
|
|
5869
|
+
'Download',
|
|
5870
|
+
'<input class="pr-inp" id="pp-download" type="text" value="'+esc(el.getAttribute('download')||'')+'" placeholder="filename">',
|
|
5871
|
+
'Title',
|
|
5872
|
+
'<input class="pr-inp" id="pp-link-title" type="text" value="'+esc(el.getAttribute('title')||'')+'">'
|
|
5873
|
+
) +
|
|
5874
|
+
pr2(
|
|
5875
|
+
'Hreflang',
|
|
5876
|
+
'<input class="pr-inp" id="pp-hreflang" type="text" value="'+esc(el.getAttribute('hreflang')||'')+'" placeholder="en">',
|
|
5877
|
+
'Type',
|
|
5878
|
+
'<input class="pr-inp" id="pp-link-type" type="text" value="'+esc(el.getAttribute('type')||'')+'" placeholder="MIME type">'
|
|
5879
|
+
) +
|
|
5880
|
+
pr(
|
|
5881
|
+
'Referrer policy',
|
|
5882
|
+
'<select class="pr-inp" id="pp-referrerpolicy">'+selOpts(['','no-referrer','no-referrer-when-downgrade','origin','origin-when-cross-origin','same-origin','strict-origin','strict-origin-when-cross-origin','unsafe-url'],el.getAttribute('referrerpolicy')||'')+'</select>'
|
|
5883
|
+
)
|
|
5884
|
+
);
|
|
5885
|
+
}
|
|
5886
|
+
|
|
5887
|
+
function setOptionalAnchorAttr(el, name, value) {
|
|
5888
|
+
if (!el || !name) return;
|
|
5889
|
+
var v = value == null ? '' : String(value).trim();
|
|
5890
|
+
if (v) el.setAttribute(name, v);
|
|
5891
|
+
else el.removeAttribute(name);
|
|
5892
|
+
}
|
|
4826
5893
|
function openCustomCssModal() {
|
|
4827
5894
|
var modal = document.getElementById('custom-css-modal');
|
|
4828
5895
|
var ta = document.getElementById('custom-css-modal-textarea');
|
|
@@ -5048,7 +6115,7 @@ function renderRightPanel(el) {
|
|
|
5048
6115
|
|
|
5049
6116
|
// \u2500\u2500 Typography \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5050
6117
|
document.getElementById('acc-body-typography').innerHTML =
|
|
5051
|
-
pr('Color', '<input type="color" class="pr-color" id="pp-color" value="'+esc(rgbToHex(cs.color))+'"><span style="font-size:11px;color:var(--text-3);flex:1;font-family:
|
|
6118
|
+
pr('Color', '<input type="color" class="pr-color" id="pp-color" value="'+esc(rgbToHex(cs.color))+'"><span style="font-size:11px;color:var(--text-3);flex:1;font-family:var(--font-mono)">'+esc(cs.color)+'</span>') +
|
|
5052
6119
|
pr2('Font size', '<input class="pr-inp" type="number" id="pp-fs" min="8" max="200" value="'+parseInt(cs.fontSize||'16')+'">',
|
|
5053
6120
|
'Font weight', '<select class="pr-inp" id="pp-fw">'+weightOpts(cs.fontWeight)+'</select>') +
|
|
5054
6121
|
pr('Font family', '<input class="pr-inp" id="pp-ff" type="text" value="'+esc(el.style.fontFamily||'')+'" placeholder="inherit">') +
|
|
@@ -5060,7 +6127,7 @@ function renderRightPanel(el) {
|
|
|
5060
6127
|
// \u2500\u2500 Background \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5061
6128
|
var bgiVal = (el.style.backgroundImage||'').replace(/url(['"]?([^'"]+)['"]?)/,'$1');
|
|
5062
6129
|
document.getElementById('acc-body-background').innerHTML =
|
|
5063
|
-
pr('Color', '<input type="color" class="pr-color" id="pp-bg" value="'+esc(rgbToHex(cs.backgroundColor))+'"><span style="font-size:11px;color:var(--text-3);flex:1;font-family:
|
|
6130
|
+
pr('Color', '<input type="color" class="pr-color" id="pp-bg" value="'+esc(rgbToHex(cs.backgroundColor))+'"><span style="font-size:11px;color:var(--text-3);flex:1;font-family:var(--font-mono)">'+esc(cs.backgroundColor)+'</span>') +
|
|
5064
6131
|
pr('Image URL', '<input class="pr-inp" id="pp-bgi" type="url" value="'+esc(bgiVal)+'" placeholder="https://\u2026">') +
|
|
5065
6132
|
pr2('Size', '<select class="pr-inp" id="pp-bgs">'+selOpts(['auto','cover','contain'],el.style.backgroundSize||'auto')+'</select>',
|
|
5066
6133
|
'Repeat', '<select class="pr-inp" id="pp-bgr">'+selOpts(['repeat','no-repeat','repeat-x','repeat-y'],el.style.backgroundRepeat||'repeat')+'</select>');
|
|
@@ -5130,9 +6197,9 @@ function renderRightPanel(el) {
|
|
|
5130
6197
|
// \u2500\u2500 Device styling rules \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5131
6198
|
document.getElementById('acc-body-device').innerHTML =
|
|
5132
6199
|
subLbl('Mobile (\u2264768px)') +
|
|
5133
|
-
'<textarea class="pr-inp" id="pp-mob-css" style="width:100%;min-height:60px;font-family:
|
|
6200
|
+
'<textarea class="pr-inp" id="pp-mob-css" style="width:100%;min-height:60px;font-family:var(--font-mono);font-size:11px;margin-bottom:8px" placeholder="/* styles for mobile */">'+esc(el.dataset.mobileCss||'')+'</textarea>' +
|
|
5134
6201
|
subLbl('Tablet (\u22641024px)') +
|
|
5135
|
-
'<textarea class="pr-inp" id="pp-tab-css" style="width:100%;min-height:60px;font-family:
|
|
6202
|
+
'<textarea class="pr-inp" id="pp-tab-css" style="width:100%;min-height:60px;font-family:var(--font-mono);font-size:11px" placeholder="/* styles for tablet */">'+esc(el.dataset.tabletCss||'')+'</textarea>';
|
|
5136
6203
|
|
|
5137
6204
|
// \u2500\u2500 CSS and Classes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5138
6205
|
document.getElementById('acc-body-css').innerHTML =
|
|
@@ -5143,27 +6210,54 @@ function renderRightPanel(el) {
|
|
|
5143
6210
|
'<i class="bi bi-fullscreen"></i>' +
|
|
5144
6211
|
'</button>' +
|
|
5145
6212
|
'</div>' +
|
|
5146
|
-
'<textarea class="pr-inp" id="pp-css" style="width:100%;min-height:80px;font-family:
|
|
6213
|
+
'<textarea class="pr-inp" id="pp-css" style="width:100%;min-height:80px;font-family:var(--font-mono);font-size:11px" placeholder="color: red; font-size: 16px;">'+esc(el.getAttribute('style')||'')+'</textarea>';
|
|
5147
6214
|
|
|
5148
6215
|
// \u2500\u2500 Attributes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5149
6216
|
var attrHtml =
|
|
5150
6217
|
pr('ID', '<input class="pr-inp" id="pp-id" type="text" value="'+esc(el.id||'')+'" placeholder="element-id">');
|
|
5151
|
-
if (tag==='a') attrHtml +=
|
|
5152
|
-
pr('Href', '<input class="pr-inp" id="pp-href" type="url" value="'+esc(el.getAttribute('href')||'')+'" placeholder="https://">') +
|
|
5153
|
-
pr('Target', '<select class="pr-inp" id="pp-target">'+selOpts(['','_blank','_self','_parent'],el.getAttribute('target')||'')+'</select>');
|
|
5154
6218
|
if (tag==='img') attrHtml +=
|
|
5155
6219
|
pr('Src', '<input class="pr-inp" id="pp-src" type="url" value="'+esc(el.getAttribute('src')||'')+'">') +
|
|
5156
6220
|
pr('Alt', '<input class="pr-inp" id="pp-alt" type="text" value="'+esc(el.getAttribute('alt')||'')+'">');
|
|
5157
|
-
if (tag==='
|
|
6221
|
+
if (tag==='textarea') attrHtml +=
|
|
5158
6222
|
pr('Placeholder', '<input class="pr-inp" id="pp-ph" type="text" value="'+esc(el.getAttribute('placeholder')||'')+'">');
|
|
5159
6223
|
document.getElementById('acc-body-attributes').innerHTML = attrHtml;
|
|
5160
6224
|
|
|
5161
6225
|
// \u2500\u2500 HTML Content \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
6226
|
+
var contentHtml = '';
|
|
6227
|
+
if (isLinkElement(el)) contentHtml += buildAnchorContentFieldsHtml(el);
|
|
6228
|
+
if (isFormControlElement(el)) {
|
|
6229
|
+
contentHtml +=
|
|
6230
|
+
subLbl('Value') +
|
|
6231
|
+
'<textarea class="pr-inp" id="pp-value" style="width:100%;min-height:44px;margin-bottom:8px">'+esc(getFormControlValue(el))+'</textarea>';
|
|
6232
|
+
}
|
|
6233
|
+
if (tag==='input') {
|
|
6234
|
+
contentHtml +=
|
|
6235
|
+
subLbl('Placeholder') +
|
|
6236
|
+
'<input class="pr-inp" id="pp-ph" type="text" value="'+esc(el.getAttribute('placeholder')||'')+'" style="width:100%;margin-bottom:8px">';
|
|
6237
|
+
}
|
|
6238
|
+
if (tag==='video') {
|
|
6239
|
+
contentHtml +=
|
|
6240
|
+
subLbl('Src') +
|
|
6241
|
+
'<input class="pr-inp" id="pp-video-src" type="url" value="'+esc(getVideoSrc(el))+'" placeholder="https://example.com/video.mp4" style="width:100%;margin-bottom:8px">';
|
|
6242
|
+
}
|
|
6243
|
+
if (isYoutubeVideoElement(el)) {
|
|
6244
|
+
contentHtml +=
|
|
6245
|
+
subLbl('YouTube video ID') +
|
|
6246
|
+
'<input class="pr-inp" id="pp-youtube-id" type="text" value="'+esc(getYoutubeVideoId(el))+'" placeholder="dQw4w9WgXcQ" style="width:100%;margin-bottom:8px">';
|
|
6247
|
+
}
|
|
6248
|
+
if (isVimeoVideoElement(el)) {
|
|
6249
|
+
contentHtml +=
|
|
6250
|
+
subLbl('Vimeo video ID') +
|
|
6251
|
+
'<input class="pr-inp" id="pp-vimeo-id" type="text" value="'+esc(getVimeoVideoId(el))+'" placeholder="76979871" style="width:100%;margin-bottom:8px">';
|
|
6252
|
+
}
|
|
6253
|
+
if (tag!=='input' && tag!=='video' && !isEmbeddedVideoIframe(el)) {
|
|
6254
|
+
contentHtml +=
|
|
6255
|
+
subLbl('Inner Text') +
|
|
6256
|
+
'<textarea class="pr-inp" id="pp-text" style="width:100%;min-height:60px;margin-bottom:8px">'+esc(el.innerText||'')+'</textarea>' +
|
|
6257
|
+
subLbl('Inner HTML') +
|
|
6258
|
+
'<textarea class="pr-inp" id="pp-html" style="width:100%;min-height:70px;font-family:var(--font-mono);font-size:11px">'+esc(el.innerHTML||'')+'</textarea>';
|
|
6259
|
+
}
|
|
6260
|
+
document.getElementById('acc-body-content').innerHTML = contentHtml;
|
|
5167
6261
|
|
|
5168
6262
|
// \u2500\u2500 Wire up all inputs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5169
6263
|
var bindings = [
|
|
@@ -5214,13 +6308,20 @@ function renderRightPanel(el) {
|
|
|
5214
6308
|
['pp-cls', function(v){el.className=v}],
|
|
5215
6309
|
['pp-css', function(v){el.setAttribute('style',v)}],
|
|
5216
6310
|
['pp-id', function(v){el.id=v}],
|
|
5217
|
-
['pp-href', function(v){el
|
|
5218
|
-
['pp-target', function(v){el
|
|
6311
|
+
['pp-href', function(v){setOptionalAnchorAttr(el,'href',v)}],
|
|
6312
|
+
['pp-target', function(v){setOptionalAnchorAttr(el,'target',v)}],
|
|
6313
|
+
['pp-rel', function(v){setOptionalAnchorAttr(el,'rel',v)}],
|
|
6314
|
+
['pp-download', function(v){setOptionalAnchorAttr(el,'download',v)}],
|
|
6315
|
+
['pp-link-title', function(v){setOptionalAnchorAttr(el,'title',v)}],
|
|
6316
|
+
['pp-hreflang', function(v){setOptionalAnchorAttr(el,'hreflang',v)}],
|
|
6317
|
+
['pp-link-type', function(v){setOptionalAnchorAttr(el,'type',v)}],
|
|
6318
|
+
['pp-referrerpolicy', function(v){setOptionalAnchorAttr(el,'referrerpolicy',v)}],
|
|
5219
6319
|
['pp-src', function(v){el.setAttribute('src',v)}],
|
|
6320
|
+
['pp-video-src', function(v){setVideoSrc(el, v)}],
|
|
6321
|
+
['pp-youtube-id', function(v){setYoutubeVideoId(el, v)}],
|
|
6322
|
+
['pp-vimeo-id', function(v){setVimeoVideoId(el, v)}],
|
|
5220
6323
|
['pp-alt', function(v){el.setAttribute('alt',v)}],
|
|
5221
6324
|
['pp-ph', function(v){el.setAttribute('placeholder',v)}],
|
|
5222
|
-
['pp-text', function(v){el.innerText=v}],
|
|
5223
|
-
['pp-html', function(v){el.innerHTML=v}],
|
|
5224
6325
|
];
|
|
5225
6326
|
var sel = buildSelector(el);
|
|
5226
6327
|
bindings.forEach(function(b){
|
|
@@ -5245,6 +6346,45 @@ function renderRightPanel(el) {
|
|
|
5245
6346
|
inp.addEventListener('change', onValueChange);
|
|
5246
6347
|
}
|
|
5247
6348
|
});
|
|
6349
|
+
wireContentFieldSync(el, sel);
|
|
6350
|
+
}
|
|
6351
|
+
|
|
6352
|
+
function wireContentFieldSync(el, sel) {
|
|
6353
|
+
var textInp = document.getElementById('pp-text');
|
|
6354
|
+
var htmlInp = document.getElementById('pp-html');
|
|
6355
|
+
var valueInp = document.getElementById('pp-value');
|
|
6356
|
+
var syncing = false;
|
|
6357
|
+
function applyContentChange(changedId) {
|
|
6358
|
+
if (syncing) return;
|
|
6359
|
+
syncing = true;
|
|
6360
|
+
try {
|
|
6361
|
+
var orig = getOriginalValue(changedId, el);
|
|
6362
|
+
if (changedId === 'pp-value') {
|
|
6363
|
+
el.value = valueInp.value;
|
|
6364
|
+
logChange(sel, 'pp-value', valueInp.value, el, orig);
|
|
6365
|
+
} else if (changedId === 'pp-text') {
|
|
6366
|
+
el.innerText = textInp.value;
|
|
6367
|
+
htmlInp.value = el.innerHTML;
|
|
6368
|
+
logChange(sel, 'pp-text', textInp.value, el, orig);
|
|
6369
|
+
} else {
|
|
6370
|
+
el.innerHTML = htmlInp.value;
|
|
6371
|
+
textInp.value = el.innerText;
|
|
6372
|
+
logChange(sel, 'pp-html', htmlInp.value, el, orig);
|
|
6373
|
+
}
|
|
6374
|
+
} finally {
|
|
6375
|
+
syncing = false;
|
|
6376
|
+
}
|
|
6377
|
+
}
|
|
6378
|
+
if (valueInp && isFormControlElement(el)) {
|
|
6379
|
+
valueInp.addEventListener('input', function() { applyContentChange('pp-value'); });
|
|
6380
|
+
valueInp.addEventListener('change', function() { applyContentChange('pp-value'); });
|
|
6381
|
+
}
|
|
6382
|
+
if (textInp && htmlInp) {
|
|
6383
|
+
textInp.addEventListener('input', function() { applyContentChange('pp-text'); });
|
|
6384
|
+
textInp.addEventListener('change', function() { applyContentChange('pp-text'); });
|
|
6385
|
+
htmlInp.addEventListener('input', function() { applyContentChange('pp-html'); });
|
|
6386
|
+
htmlInp.addEventListener('change', function() { applyContentChange('pp-html'); });
|
|
6387
|
+
}
|
|
5248
6388
|
}
|
|
5249
6389
|
|
|
5250
6390
|
// \u2500\u2500 Selector helper \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
@@ -5465,6 +6605,100 @@ function repositionDragSibling(dragEl, clientY) {
|
|
|
5465
6605
|
}
|
|
5466
6606
|
}
|
|
5467
6607
|
|
|
6608
|
+
function isMoveSwapSkippableSibling(el) {
|
|
6609
|
+
if (!el || el.nodeType !== 1) return true;
|
|
6610
|
+
if (isDomTreeSkippableTagName(el.tagName)) return true;
|
|
6611
|
+
try {
|
|
6612
|
+
if (el.hasAttribute && el.hasAttribute('hidden')) return true;
|
|
6613
|
+
if (el.getAttribute && el.getAttribute('data-vve-hidden') === '1') return true;
|
|
6614
|
+
} catch(_) {}
|
|
6615
|
+
try {
|
|
6616
|
+
if (el.style && el.style.display === 'none') return true;
|
|
6617
|
+
if (el.style && el.style.visibility === 'hidden') return true;
|
|
6618
|
+
} catch(_) {}
|
|
6619
|
+
try {
|
|
6620
|
+
var view = el.ownerDocument && el.ownerDocument.defaultView;
|
|
6621
|
+
var cs = view && view.getComputedStyle ? view.getComputedStyle(el) : null;
|
|
6622
|
+
if (cs && (cs.display === 'none' || cs.visibility === 'hidden')) return true;
|
|
6623
|
+
} catch(_) {}
|
|
6624
|
+
return false;
|
|
6625
|
+
}
|
|
6626
|
+
|
|
6627
|
+
function findMoveSwapSibling(el, direction) {
|
|
6628
|
+
if (!el) return null;
|
|
6629
|
+
var node = direction < 0 ? el.previousElementSibling : el.nextElementSibling;
|
|
6630
|
+
while (node && isMoveSwapSkippableSibling(node)) {
|
|
6631
|
+
node = direction < 0 ? node.previousElementSibling : node.nextElementSibling;
|
|
6632
|
+
}
|
|
6633
|
+
return node;
|
|
6634
|
+
}
|
|
6635
|
+
|
|
6636
|
+
function isMoveParentEscapeBlocked(parent) {
|
|
6637
|
+
if (!parent || parent.nodeType !== 1) return true;
|
|
6638
|
+
var tag = (parent.tagName || '').toLowerCase();
|
|
6639
|
+
if (tag === 'html' || tag === 'body') return true;
|
|
6640
|
+
try {
|
|
6641
|
+
var doc = parent.ownerDocument;
|
|
6642
|
+
if (doc && (parent === doc.documentElement || parent === doc.body)) return true;
|
|
6643
|
+
} catch(_) {}
|
|
6644
|
+
return false;
|
|
6645
|
+
}
|
|
6646
|
+
|
|
6647
|
+
/** When no visual sibling exists, lift the node to the grandparent (before/after its parent). */
|
|
6648
|
+
function canMoveEscapeToParent(el, direction) {
|
|
6649
|
+
if (!el || !el.parentElement) return false;
|
|
6650
|
+
var parent = el.parentElement;
|
|
6651
|
+
if (isMoveParentEscapeBlocked(parent) || !parent.parentElement) return false;
|
|
6652
|
+
if (findMoveSwapSibling(el, direction)) return false;
|
|
6653
|
+
return true;
|
|
6654
|
+
}
|
|
6655
|
+
|
|
6656
|
+
function canMoveElDirection(el, direction) {
|
|
6657
|
+
if (!el || !el.parentElement) return false;
|
|
6658
|
+
return !!findMoveSwapSibling(el, direction) || canMoveEscapeToParent(el, direction);
|
|
6659
|
+
}
|
|
6660
|
+
|
|
6661
|
+
function moveElByDirection(el, direction) {
|
|
6662
|
+
if (!el || !el.parentElement) return false;
|
|
6663
|
+
var parent = el.parentElement;
|
|
6664
|
+
var sibling = findMoveSwapSibling(el, direction);
|
|
6665
|
+
if (sibling) {
|
|
6666
|
+
if (direction < 0) parent.insertBefore(el, sibling);
|
|
6667
|
+
else parent.insertBefore(sibling, el);
|
|
6668
|
+
return true;
|
|
6669
|
+
}
|
|
6670
|
+
if (!canMoveEscapeToParent(el, direction)) return false;
|
|
6671
|
+
var grandparent = parent.parentElement;
|
|
6672
|
+
if (!grandparent) return false;
|
|
6673
|
+
if (direction < 0) grandparent.insertBefore(el, parent);
|
|
6674
|
+
else grandparent.insertBefore(el, parent.nextSibling);
|
|
6675
|
+
return true;
|
|
6676
|
+
}
|
|
6677
|
+
|
|
6678
|
+
function syncMoveFloaterButtons(el) {
|
|
6679
|
+
var upBtn = document.getElementById('sf-move-up');
|
|
6680
|
+
var downBtn = document.getElementById('sf-move-down');
|
|
6681
|
+
if (!upBtn || !downBtn) return;
|
|
6682
|
+
var canUp = canMoveElDirection(el, -1);
|
|
6683
|
+
var canDown = canMoveElDirection(el, 1);
|
|
6684
|
+
upBtn.disabled = !canUp;
|
|
6685
|
+
downBtn.disabled = !canDown;
|
|
6686
|
+
if (canUp) {
|
|
6687
|
+
upBtn.title = findMoveSwapSibling(el, -1)
|
|
6688
|
+
? 'Move up'
|
|
6689
|
+
: 'Move up (out of container)';
|
|
6690
|
+
} else {
|
|
6691
|
+
upBtn.title = 'Cannot move up';
|
|
6692
|
+
}
|
|
6693
|
+
if (canDown) {
|
|
6694
|
+
downBtn.title = findMoveSwapSibling(el, 1)
|
|
6695
|
+
? 'Move down'
|
|
6696
|
+
: 'Move down (out of container)';
|
|
6697
|
+
} else {
|
|
6698
|
+
downBtn.title = 'Cannot move down';
|
|
6699
|
+
}
|
|
6700
|
+
}
|
|
6701
|
+
|
|
5468
6702
|
function recordReorderAfterDrag(movedEl) {
|
|
5469
6703
|
if (!activeVarId || !movedEl || !movedEl.parentElement) return;
|
|
5470
6704
|
var prev = movedEl.previousElementSibling;
|
|
@@ -5493,13 +6727,11 @@ function recordReorderAfterDrag(movedEl) {
|
|
|
5493
6727
|
}
|
|
5494
6728
|
|
|
5495
6729
|
function moveSelectedElByDirection(direction) {
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
if (!
|
|
5500
|
-
|
|
5501
|
-
else p.insertBefore(sibling, selectedEl);
|
|
5502
|
-
recordReorderAfterDrag(selectedEl);
|
|
6730
|
+
var el = recoverSelectedElement(false) || selectedEl;
|
|
6731
|
+
if (!el || !el.parentElement) return;
|
|
6732
|
+
selectedEl = el;
|
|
6733
|
+
if (!moveElByDirection(el, direction)) return;
|
|
6734
|
+
recordReorderAfterDrag(el);
|
|
5503
6735
|
saveCurrentVariationHtml();
|
|
5504
6736
|
recomputeEditorDirty();
|
|
5505
6737
|
scheduleDomTreeRefresh();
|
|
@@ -5599,6 +6831,7 @@ function attachClickHandler() {
|
|
|
5599
6831
|
deselectElement(); return;
|
|
5600
6832
|
}
|
|
5601
6833
|
selectElement(target);
|
|
6834
|
+
if (currentMainTab !== 'design') switchMainTab('design');
|
|
5602
6835
|
}, true);
|
|
5603
6836
|
} catch(_) {}
|
|
5604
6837
|
}
|
|
@@ -5703,15 +6936,18 @@ function syncIframeInteractions(reason) {
|
|
|
5703
6936
|
// \u2500\u2500 HTML insertion (Components / Sections) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5704
6937
|
/** Full snippets for Vvveb keys whose html field is placeholder text, not markup. */
|
|
5705
6938
|
var VVVEB_INSERT_HTML_OVERRIDES = {
|
|
5706
|
-
'html/gridrow': '<div
|
|
5707
|
-
'html/gridcolumn': '<div
|
|
5708
|
-
'html/container': '<div
|
|
5709
|
-
'html/btn-link': '<a
|
|
5710
|
-
'html/btn': '<button type="button"
|
|
5711
|
-
'html/
|
|
5712
|
-
'html/
|
|
5713
|
-
'html/
|
|
5714
|
-
'html/
|
|
6939
|
+
'html/gridrow': '<div style="display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px;width:100%;box-sizing:border-box"><div style="padding:16px;background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px"><p style="margin:0">Column 1</p></div><div style="padding:16px;background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px"><p style="margin:0">Column 2</p></div><div style="padding:16px;background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px"><p style="margin:0">Column 3</p></div></div>',
|
|
6940
|
+
'html/gridcolumn': '<div style="padding:16px;background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px;min-height:60px;box-sizing:border-box"><p style="margin:0">New column</p></div>',
|
|
6941
|
+
'html/container': '<div style="width:100%;max-width:960px;margin:0 auto;padding:16px;box-sizing:border-box"><p style="margin:0">Container</p></div>',
|
|
6942
|
+
'html/btn-link': '<a href="#" style="display:inline-block;padding:10px 20px;font-size:14px;font-weight:600;line-height:1.2;color:#fff;background:#2563eb;border-radius:6px;text-decoration:none">Primary button</a>',
|
|
6943
|
+
'html/btn': '<button type="button" style="display:inline-block;padding:10px 20px;font-size:14px;font-weight:600;line-height:1.2;color:#fff;background:#2563eb;border:none;border-radius:6px;cursor:pointer">Primary</button>',
|
|
6944
|
+
'html/badge': '<span style="display:inline-flex;align-items:center;padding:4px 10px;font-size:12px;font-weight:600;line-height:1;letter-spacing:.02em;color:#fff;background:#2563eb;border-radius:999px">Badge</span>',
|
|
6945
|
+
'html/alert': '<div role="alert" style="padding:12px 16px;font-size:14px;line-height:1.5;color:#0c4a6e;background:#e0f2fe;border:1px solid #7dd3fc;border-radius:6px">Alert message</div>',
|
|
6946
|
+
'html/card': '<div style="border:1px solid #e2e8f0;border-radius:8px;background:#fff;overflow:hidden;max-width:360px;box-shadow:0 1px 3px rgba(0,0,0,.08)"><div style="padding:20px"><h5 style="margin:0 0 8px;font-size:18px;font-weight:700;color:#0f172a">Card title</h5><p style="margin:0;font-size:14px;line-height:1.5;color:#475569">Card content</p></div></div>',
|
|
6947
|
+
'html/pageitem': '<li style="display:inline-block;margin:0 4px"><a href="#" style="display:inline-block;padding:6px 12px;font-size:14px;color:#2563eb;border:1px solid #cbd5e1;border-radius:6px;text-decoration:none">1</a></li>',
|
|
6948
|
+
'html/breadcrumbitem': '<li style="display:inline;font-size:14px;color:#64748b"><a href="#" style="color:#2563eb;text-decoration:none">Item</a></li>',
|
|
6949
|
+
'html/listitem': '<li style="padding:10px 14px;font-size:14px;color:#334155;border:1px solid #e2e8f0;border-radius:6px;background:#fff">List item</li>',
|
|
6950
|
+
'html/tablebody': '<tbody><tr><td style="padding:10px 12px;border:1px solid #e2e8f0;font-size:14px">Cell</td></tr></tbody>',
|
|
5715
6951
|
};
|
|
5716
6952
|
|
|
5717
6953
|
function buildHtmlFromVvvebComponent(comp, typeKey) {
|
|
@@ -5739,7 +6975,7 @@ function insertVvvebComponent(typeKey) {
|
|
|
5739
6975
|
insertHtml(html);
|
|
5740
6976
|
}
|
|
5741
6977
|
|
|
5742
|
-
function insertHtml(html) {
|
|
6978
|
+
function insertHtml(html, options) {
|
|
5743
6979
|
if (!html) return;
|
|
5744
6980
|
try {
|
|
5745
6981
|
var iframe = document.getElementById('iframeId');
|
|
@@ -5767,7 +7003,17 @@ function insertHtml(html) {
|
|
|
5767
7003
|
} else {
|
|
5768
7004
|
doc.body.appendChild(frag);
|
|
5769
7005
|
}
|
|
7006
|
+
if (firstEl) {
|
|
7007
|
+
try {
|
|
7008
|
+
firstEl.setAttribute('data-vve-instance', generateVveInstanceId());
|
|
7009
|
+
} catch(_) {}
|
|
7010
|
+
htmlStr = firstEl.outerHTML;
|
|
7011
|
+
}
|
|
5770
7012
|
if (firstEl) selectElement(firstEl);
|
|
7013
|
+
var accSection = options && options.defaultAccSection;
|
|
7014
|
+
if (accSection) {
|
|
7015
|
+
requestAnimationFrame(function() { focusDesignAccordionSection(accSection); });
|
|
7016
|
+
}
|
|
5771
7017
|
if (activeVarId) {
|
|
5772
7018
|
var insertRow = {
|
|
5773
7019
|
selector: anchorSel,
|
|
@@ -5799,7 +7045,7 @@ function renderSidebar(filter) {
|
|
|
5799
7045
|
baseFiltered.forEach(function(c) {
|
|
5800
7046
|
var item = document.createElement('div'); item.className = 'cg-item'; item.title = 'Insert ' + c.name;
|
|
5801
7047
|
item.innerHTML = '<div class="cg-icon"><i class="bi ' + c.icon + '"></i></div><div class="cg-name">' + c.name + '</div>';
|
|
5802
|
-
item.onclick = function() { insertHtml(c.html); };
|
|
7048
|
+
item.onclick = function() { insertHtml(c.html, { defaultAccSection: c.defaultAccSection }); };
|
|
5803
7049
|
g1.appendChild(item);
|
|
5804
7050
|
});
|
|
5805
7051
|
compTab.appendChild(g1);
|
|
@@ -5839,7 +7085,7 @@ function renderSidebar(filter) {
|
|
|
5839
7085
|
var ch = document.createElement('div'); ch.className = 'cg-hdr'; ch.textContent = 'CRO Components'; secTab.appendChild(ch);
|
|
5840
7086
|
croFiltered.forEach(function(sec) {
|
|
5841
7087
|
var item = document.createElement('div'); item.className = 'sec-item';
|
|
5842
|
-
item.innerHTML = '<div class="sec-thumb">'+(sec
|
|
7088
|
+
item.innerHTML = '<div class="sec-thumb">'+renderCroSectionThumb(sec)+'</div><div class="sec-info"><div class="sec-name">'+sec.name+'</div>'+(sec.desc?'<div class="sec-desc">'+sec.desc+'</div>':'')+'</div>';
|
|
5843
7089
|
item.onclick = function() { insertHtml(sec.html); };
|
|
5844
7090
|
secTab.appendChild(item);
|
|
5845
7091
|
});
|
|
@@ -5869,11 +7115,7 @@ document.getElementById('comp-search').addEventListener('input', function() {
|
|
|
5869
7115
|
});
|
|
5870
7116
|
var btnAddElement = document.getElementById('btn-add-element');
|
|
5871
7117
|
if (btnAddElement) {
|
|
5872
|
-
btnAddElement.addEventListener('click',
|
|
5873
|
-
e.preventDefault();
|
|
5874
|
-
e.stopPropagation();
|
|
5875
|
-
toggleSectionComponentsPanel();
|
|
5876
|
-
});
|
|
7118
|
+
btnAddElement.addEventListener('click', handleAddElementClick);
|
|
5877
7119
|
}
|
|
5878
7120
|
|
|
5879
7121
|
// \u2500\u2500 Save / Close \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
@@ -6078,13 +7320,19 @@ function bindLoadingTooltipPositioning() {
|
|
|
6078
7320
|
// \u2500\u2500 Init \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
6079
7321
|
function registerCROSections() {
|
|
6080
7322
|
if (typeof Vvveb === 'undefined' || !Vvveb.Sections) return;
|
|
6081
|
-
CRO_SECTIONS.forEach(function(sec) {
|
|
7323
|
+
CRO_SECTIONS.forEach(function(sec) {
|
|
7324
|
+
Vvveb.Sections.add(sec.key, {
|
|
7325
|
+
name: sec.name,
|
|
7326
|
+
image: sec.image ? (CRO_SECTION_IMAGE_ROUTE + sec.image) : '',
|
|
7327
|
+
html: sec.html,
|
|
7328
|
+
});
|
|
7329
|
+
});
|
|
6082
7330
|
}
|
|
6083
7331
|
|
|
6084
7332
|
window.addEventListener('load', function() {
|
|
6085
7333
|
registerCROSections();
|
|
6086
7334
|
bindViewportControls();
|
|
6087
|
-
switchSectionComponentsTab(currentSectionComponentsTab);
|
|
7335
|
+
// switchSectionComponentsTab(currentSectionComponentsTab);
|
|
6088
7336
|
renderElementsTree(document.getElementById('comp-search').value);
|
|
6089
7337
|
vvvebReady = true;
|
|
6090
7338
|
bindLoadingTooltipPositioning();
|
|
@@ -6157,6 +7405,10 @@ window.addEventListener('load', function() {
|
|
|
6157
7405
|
syncIframeInteractions('iframe-load');
|
|
6158
7406
|
});
|
|
6159
7407
|
|
|
7408
|
+
var sfAdd = document.getElementById('sf-add');
|
|
7409
|
+
if (sfAdd) {
|
|
7410
|
+
sfAdd.addEventListener('click', handleAddElementClick);
|
|
7411
|
+
}
|
|
6160
7412
|
var sfMoveUp = document.getElementById('sf-move-up');
|
|
6161
7413
|
if (sfMoveUp) {
|
|
6162
7414
|
sfMoveUp.addEventListener('click', function(e) {
|
|
@@ -6256,6 +7508,20 @@ function createVisualEditorMiddleware(options) {
|
|
|
6256
7508
|
res.end(buildVvvebEditorHtml());
|
|
6257
7509
|
return;
|
|
6258
7510
|
}
|
|
7511
|
+
if (pathname.startsWith(CRO_SECTION_IMAGE_ROUTE)) {
|
|
7512
|
+
const filename = pathname.slice(CRO_SECTION_IMAGE_ROUTE.length);
|
|
7513
|
+
const filePath = resolveCroSectionImagePath(filename);
|
|
7514
|
+
if (!filePath) {
|
|
7515
|
+
res.statusCode = 404;
|
|
7516
|
+
res.end("Not found");
|
|
7517
|
+
return;
|
|
7518
|
+
}
|
|
7519
|
+
res.setHeader("Content-Type", "image/png");
|
|
7520
|
+
res.setHeader("Cache-Control", "public, max-age=86400");
|
|
7521
|
+
setFrameHeaders(req, res);
|
|
7522
|
+
res.end(fs__default.default.readFileSync(filePath));
|
|
7523
|
+
return;
|
|
7524
|
+
}
|
|
6259
7525
|
if (pathname === "/api/generate-test" && enableGenerateTestApi) {
|
|
6260
7526
|
if (req.method === "OPTIONS") {
|
|
6261
7527
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
@@ -6394,7 +7660,6 @@ function createVisualEditorMiddleware(options) {
|
|
|
6394
7660
|
const trackingMarkersForRequest = mergeTrackingMarkers(
|
|
6395
7661
|
extraTrackingMarkersForRequest
|
|
6396
7662
|
);
|
|
6397
|
-
console.log("trackingMarkersForRequest", trackingMarkersForRequest);
|
|
6398
7663
|
const strictFreezeParam = (url.searchParams.get("strictObserverFreeze") || "").toLowerCase();
|
|
6399
7664
|
const strictObserverFreezeForRequest = strictFreezeParam === "1" || strictFreezeParam === "true" || strictFreezeParam === "yes" ? true : strictFreezeParam === "0" || strictFreezeParam === "false" || strictFreezeParam === "no" ? false : strictObserverFreeze;
|
|
6400
7665
|
if (!targetUrl) {
|
|
@@ -7095,6 +8360,13 @@ function visualEditorProxyPlugin(options) {
|
|
|
7095
8360
|
generateBundle() {
|
|
7096
8361
|
this.emitFile({ type: "asset", fileName: "bridge.js", source: BRIDGE_SCRIPT });
|
|
7097
8362
|
this.emitFile({ type: "asset", fileName: "vvveb-editor/index.html", source: buildVvvebEditorHtml() });
|
|
8363
|
+
for (const imagePath of listCroSectionImageFiles()) {
|
|
8364
|
+
this.emitFile({
|
|
8365
|
+
type: "asset",
|
|
8366
|
+
fileName: path__default.default.join("images", "cro-sections", path__default.default.basename(imagePath)),
|
|
8367
|
+
source: fs__default.default.readFileSync(imagePath)
|
|
8368
|
+
});
|
|
8369
|
+
}
|
|
7098
8370
|
},
|
|
7099
8371
|
configureServer(server) {
|
|
7100
8372
|
server.middlewares.use(mw);
|