@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.js
CHANGED
|
@@ -3,6 +3,108 @@ import path from 'path';
|
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
|
|
5
5
|
// src/visualEditorProxyPlugin.ts
|
|
6
|
+
|
|
7
|
+
// src/croSections.ts
|
|
8
|
+
var CRO_SECTION_IMAGE_ROUTE = "/vvveb-editor-images/cro-sections/";
|
|
9
|
+
function croSectionImageFilename(key) {
|
|
10
|
+
return key.replace(/\//g, "-") + ".png";
|
|
11
|
+
}
|
|
12
|
+
var CRO_SECTIONS_BASE = [
|
|
13
|
+
{
|
|
14
|
+
key: "cro/hero",
|
|
15
|
+
name: "CRO Hero",
|
|
16
|
+
icon: "\u{1F3AF}",
|
|
17
|
+
desc: "High-converting hero section",
|
|
18
|
+
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>'
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
key: "cro/social-proof",
|
|
22
|
+
name: "Social Proof",
|
|
23
|
+
icon: "\u2B50",
|
|
24
|
+
desc: "Star rating + 3-column testimonials",
|
|
25
|
+
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>'
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
key: "cro/urgency-banner",
|
|
29
|
+
name: "Urgency Banner",
|
|
30
|
+
icon: "\u23F0",
|
|
31
|
+
desc: "Countdown timer + limited-time offer",
|
|
32
|
+
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>'
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
key: "cro/trust-badges",
|
|
36
|
+
name: "Trust Badges",
|
|
37
|
+
icon: "\u{1F6E1}\uFE0F",
|
|
38
|
+
desc: "Security seals, payment icons, guarantees",
|
|
39
|
+
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>'
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
key: "cro/cta-block",
|
|
43
|
+
name: "CTA Block",
|
|
44
|
+
icon: "\u{1F4E3}",
|
|
45
|
+
desc: "Dark high-impact call-to-action section",
|
|
46
|
+
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>'
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
key: "cro/feature-grid",
|
|
50
|
+
name: "Feature Grid",
|
|
51
|
+
icon: "\u2728",
|
|
52
|
+
desc: "3-column key benefits grid",
|
|
53
|
+
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>'
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
key: "cro/exit-intent-bar",
|
|
57
|
+
name: "Exit Intent Bar",
|
|
58
|
+
icon: "\u{1F6AA}",
|
|
59
|
+
desc: "Sticky bottom bar for exit-intent capture",
|
|
60
|
+
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>`
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
key: "cro/pricing-table",
|
|
64
|
+
name: "Pricing Table",
|
|
65
|
+
icon: "\u{1F4B0}",
|
|
66
|
+
desc: "3-tier pricing with highlighted plan",
|
|
67
|
+
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>'
|
|
68
|
+
}
|
|
69
|
+
];
|
|
70
|
+
var CRO_SECTIONS = CRO_SECTIONS_BASE.map((section) => ({
|
|
71
|
+
...section,
|
|
72
|
+
image: croSectionImageFilename(section.key)
|
|
73
|
+
}));
|
|
74
|
+
|
|
75
|
+
// src/visualEditorProxyPlugin.ts
|
|
76
|
+
var PACKAGE_ROOT = path.dirname(fileURLToPath(import.meta.url));
|
|
77
|
+
function resolveCroSectionImagePath(filename) {
|
|
78
|
+
const safe = path.basename(filename);
|
|
79
|
+
if (!safe || safe !== filename) return null;
|
|
80
|
+
const candidates = [
|
|
81
|
+
path.join(PACKAGE_ROOT, "images", "cro-sections", safe),
|
|
82
|
+
path.join(PACKAGE_ROOT, "..", "src", "images", "cro-sections", safe),
|
|
83
|
+
path.join(process.cwd(), "src", "images", "cro-sections", safe)
|
|
84
|
+
];
|
|
85
|
+
for (const candidate of candidates) {
|
|
86
|
+
try {
|
|
87
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
88
|
+
} catch (_) {
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
function listCroSectionImageFiles() {
|
|
94
|
+
const dirs = [
|
|
95
|
+
path.join(PACKAGE_ROOT, "images", "cro-sections"),
|
|
96
|
+
path.join(PACKAGE_ROOT, "..", "src", "images", "cro-sections"),
|
|
97
|
+
path.join(process.cwd(), "src", "images", "cro-sections")
|
|
98
|
+
];
|
|
99
|
+
for (const dir of dirs) {
|
|
100
|
+
try {
|
|
101
|
+
if (!fs.existsSync(dir)) continue;
|
|
102
|
+
return fs.readdirSync(dir).filter((name) => name.endsWith(".png")).map((name) => path.join(dir, name));
|
|
103
|
+
} catch (_) {
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return [];
|
|
107
|
+
}
|
|
6
108
|
var DEFAULT_TRACKING_MARKERS = [
|
|
7
109
|
"snowplow",
|
|
8
110
|
"taboola",
|
|
@@ -254,64 +356,6 @@ catch(_){}})();</script>`;
|
|
|
254
356
|
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.`;
|
|
255
357
|
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'});})();`;
|
|
256
358
|
function buildVvvebEditorHtml() {
|
|
257
|
-
const CRO_SECTIONS = [
|
|
258
|
-
{
|
|
259
|
-
key: "cro/hero",
|
|
260
|
-
name: "CRO Hero",
|
|
261
|
-
icon: "\u{1F3AF}",
|
|
262
|
-
desc: "High-converting hero section",
|
|
263
|
-
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>'
|
|
264
|
-
},
|
|
265
|
-
{
|
|
266
|
-
key: "cro/social-proof",
|
|
267
|
-
name: "Social Proof",
|
|
268
|
-
icon: "\u2B50",
|
|
269
|
-
desc: "Star rating + 3-column testimonials",
|
|
270
|
-
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>'
|
|
271
|
-
},
|
|
272
|
-
{
|
|
273
|
-
key: "cro/urgency-banner",
|
|
274
|
-
name: "Urgency Banner",
|
|
275
|
-
icon: "\u23F0",
|
|
276
|
-
desc: "Countdown timer + limited-time offer",
|
|
277
|
-
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>'
|
|
278
|
-
},
|
|
279
|
-
{
|
|
280
|
-
key: "cro/trust-badges",
|
|
281
|
-
name: "Trust Badges",
|
|
282
|
-
icon: "\u{1F6E1}\uFE0F",
|
|
283
|
-
desc: "Security seals, payment icons, guarantees",
|
|
284
|
-
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>'
|
|
285
|
-
},
|
|
286
|
-
{
|
|
287
|
-
key: "cro/cta-block",
|
|
288
|
-
name: "CTA Block",
|
|
289
|
-
icon: "\u{1F4E3}",
|
|
290
|
-
desc: "Dark high-impact call-to-action section",
|
|
291
|
-
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>'
|
|
292
|
-
},
|
|
293
|
-
{
|
|
294
|
-
key: "cro/feature-grid",
|
|
295
|
-
name: "Feature Grid",
|
|
296
|
-
icon: "\u2728",
|
|
297
|
-
desc: "3-column key benefits grid",
|
|
298
|
-
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>'
|
|
299
|
-
},
|
|
300
|
-
{
|
|
301
|
-
key: "cro/exit-intent-bar",
|
|
302
|
-
name: "Exit Intent Bar",
|
|
303
|
-
icon: "\u{1F6AA}",
|
|
304
|
-
desc: "Sticky bottom bar for exit-intent capture",
|
|
305
|
-
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>`
|
|
306
|
-
},
|
|
307
|
-
{
|
|
308
|
-
key: "cro/pricing-table",
|
|
309
|
-
name: "Pricing Table",
|
|
310
|
-
icon: "\u{1F4B0}",
|
|
311
|
-
desc: "3-tier pricing with highlighted plan",
|
|
312
|
-
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>'
|
|
313
|
-
}
|
|
314
|
-
];
|
|
315
359
|
const sectionsJson = JSON.stringify(CRO_SECTIONS);
|
|
316
360
|
return `<!DOCTYPE html>
|
|
317
361
|
<html lang="en">
|
|
@@ -319,27 +363,39 @@ function buildVvvebEditorHtml() {
|
|
|
319
363
|
<meta charset="UTF-8">
|
|
320
364
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
321
365
|
<title>Visual Editor V2</title>
|
|
366
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
367
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
368
|
+
<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">
|
|
322
369
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
|
323
370
|
<style>
|
|
324
371
|
/* \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 */
|
|
325
372
|
*{box-sizing:border-box;margin:0;padding:0}
|
|
326
|
-
html,body{height:100%;overflow:hidden;font-family
|
|
373
|
+
html,body{height:100%;overflow:hidden;font-family:var(--font-sans);font-size:13px;color:#1e293b;background:#f1f5f9}
|
|
327
374
|
|
|
328
375
|
/* \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 */
|
|
329
376
|
:root{
|
|
377
|
+
--font-inter:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
|
|
378
|
+
--font-roboto:'Roboto',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
|
|
379
|
+
--font-mono:'JetBrains Mono',ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;
|
|
380
|
+
--font-sans:var(--font-inter),var(--font-roboto),-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
|
|
330
381
|
--bg: #ffffff;
|
|
331
382
|
--bg-sub: #f8fafc;
|
|
332
|
-
--bg-hover: #
|
|
383
|
+
--bg-hover: #F5F5F5;
|
|
333
384
|
--border: #e2e8f0;
|
|
334
385
|
--border-sub: #f1f5f9;
|
|
335
386
|
--text: #404040;
|
|
336
387
|
--text-2: #475569;
|
|
337
388
|
--text-3: #94a3b8;
|
|
338
|
-
--accent: #
|
|
339
|
-
--accent-bg: #
|
|
389
|
+
--accent: #262626;
|
|
390
|
+
--accent-bg: #f5f5f5;
|
|
340
391
|
--accent-txt: #404040;
|
|
341
392
|
}
|
|
342
393
|
|
|
394
|
+
/* \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 */
|
|
395
|
+
.inter{font-family:var(--font-inter)}
|
|
396
|
+
.roboto{font-family:var(--font-roboto)}
|
|
397
|
+
.mono{font-family:var(--font-mono)}
|
|
398
|
+
|
|
343
399
|
/* \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 */
|
|
344
400
|
#app{display:flex;flex-direction:column;height:100vh}
|
|
345
401
|
#main{display:flex;flex:1;overflow:hidden;min-height:0}
|
|
@@ -417,9 +473,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
|
|
|
417
473
|
border-color:transparent;
|
|
418
474
|
}
|
|
419
475
|
.tb-dev-menu input#dev-zoom-level{
|
|
420
|
-
max-width:
|
|
421
|
-
margin-left:
|
|
476
|
+
max-width:72px;
|
|
477
|
+
margin-left:0;
|
|
422
478
|
}
|
|
479
|
+
.tb-dev-menu .row-zoom .zoom-controls{
|
|
480
|
+
display:flex;
|
|
481
|
+
align-items:center;
|
|
482
|
+
gap:6px;
|
|
483
|
+
margin-left:auto;
|
|
484
|
+
}
|
|
485
|
+
.tb-dev-menu .dev-zoom-fit-btn{
|
|
486
|
+
width:30px;
|
|
487
|
+
height:30px;
|
|
488
|
+
flex-shrink:0;
|
|
489
|
+
border:none;
|
|
490
|
+
border-radius:6px;
|
|
491
|
+
background:#fff;
|
|
492
|
+
cursor:pointer;
|
|
493
|
+
display:flex;
|
|
494
|
+
align-items:center;
|
|
495
|
+
justify-content:center;
|
|
496
|
+
color:#404040;
|
|
497
|
+
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);
|
|
498
|
+
transition:background .12s,color .12s;
|
|
499
|
+
}
|
|
500
|
+
.tb-dev-menu .dev-zoom-fit-btn:hover{background:#f4f4f5;color:#171717}
|
|
501
|
+
.tb-dev-menu .dev-zoom-fit-btn svg{display:block;width:16px;height:16px}
|
|
423
502
|
.tb-dev-menu input:focus{
|
|
424
503
|
border-color:#1A1A1A;
|
|
425
504
|
box-shadow:0 0 0 2px rgba(99,102,241,.14)
|
|
@@ -449,19 +528,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
|
|
|
449
528
|
text-overflow: ellipsis;
|
|
450
529
|
font-size: var(--font-size-sm, 14px);
|
|
451
530
|
font-style: normal;
|
|
452
|
-
font-weight: 500
|
|
531
|
+
font-weight: 500;#
|
|
453
532
|
line-height: var(--font-leading-4, 16px);
|
|
454
533
|
}
|
|
455
534
|
.tb-dev-menu .vp-preset-btn:hover,.tb-dev-menu .vp-preset-btn.active{background:#f4f4f5}
|
|
456
|
-
.tb-dev-menu .ft{
|
|
457
|
-
margin-top:10px;padding-top:8px;border-top:1px solid #ececf0;
|
|
458
|
-
display:flex;justify-content:flex-end
|
|
459
|
-
}
|
|
460
|
-
.tb-dev-menu .apply-btn{
|
|
461
|
-
border:1px solid #d4d4d8;background:#f8fafc;color:#111827;border-radius:6px;
|
|
462
|
-
height:30px;padding:0 10px;font-size:12px;font-weight:600;cursor:pointer
|
|
463
|
-
}
|
|
464
|
-
.tb-dev-menu .apply-btn:hover{background:#eef2ff;border-color:#a5b4fc}
|
|
465
535
|
/* Dark icon buttons */
|
|
466
536
|
.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}
|
|
467
537
|
.tb-dk-btn:hover{color:#e4e4e7;background:rgba(255,255,255,.07)}
|
|
@@ -492,9 +562,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
|
|
|
492
562
|
.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}
|
|
493
563
|
.tb-sim-btn:hover{background:rgba(255,255,255,.06);border-color:#52525b}
|
|
494
564
|
.tb-sim-btn i{font-size:11px}
|
|
495
|
-
.tb-fin-btn{
|
|
496
|
-
|
|
497
|
-
|
|
565
|
+
.tb-fin-btn{ border: none;
|
|
566
|
+
cursor: pointer;
|
|
567
|
+
transition: all .15s;
|
|
568
|
+
white-space: nowrap;
|
|
569
|
+
border-radius: var(--radius-md, 6px);
|
|
570
|
+
background: var(--bg-primary-default, #262626);
|
|
571
|
+
padding: 7px 10px;
|
|
572
|
+
color: var(--content-on-color, #FFF);
|
|
573
|
+
text-align: center;
|
|
574
|
+
font-family: Inter;
|
|
575
|
+
font-size: var(--font-size-sm, 14px);
|
|
576
|
+
font-style: normal;
|
|
577
|
+
font-weight: 500;
|
|
578
|
+
line-height: var(--font-leading-4, 16px);
|
|
579
|
+
}
|
|
580
|
+
.tb-fin-btn:hover{opacity:0.8;}
|
|
581
|
+
.tb-fin-btn#btn-save{
|
|
582
|
+
background: var(--bg-interactive-default, #FFF);
|
|
583
|
+
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);
|
|
584
|
+
border: none;
|
|
585
|
+
color: var(--content-success-default, #00C951);
|
|
586
|
+
font-weight: 500;
|
|
587
|
+
}
|
|
498
588
|
/* \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 */
|
|
499
589
|
.tb-page-loading{
|
|
500
590
|
display:none;flex-shrink:0;align-items:center;margin:0 10px 0 4px;
|
|
@@ -551,14 +641,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
|
|
|
551
641
|
|
|
552
642
|
/* \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 */
|
|
553
643
|
#left-panel{
|
|
554
|
-
width:
|
|
555
|
-
display:flex;flex-direction:column;flex-shrink:0;min-height:0;overflow:hidden
|
|
644
|
+
width:288px;
|
|
645
|
+
display:flex;flex-direction:column;flex-shrink:0;min-height:0;overflow:hidden;
|
|
646
|
+
border-right: 1px solid var(--border-default, #E5E5E5);
|
|
647
|
+
background: var(--cu-Background-Main, #FFF);
|
|
556
648
|
}
|
|
557
649
|
|
|
558
650
|
/* \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 */
|
|
559
651
|
#iframe-panel{
|
|
560
652
|
flex:1;background:#e8ecf0;display:flex;flex-direction:column;
|
|
561
|
-
align-items:center;justify-content:flex-start;overflow:
|
|
653
|
+
align-items:center;justify-content:flex-start;overflow:hidden;position:relative;
|
|
654
|
+
min-height:0;min-width:0
|
|
562
655
|
}
|
|
563
656
|
|
|
564
657
|
/* \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 */
|
|
@@ -579,13 +672,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
|
|
|
579
672
|
#selection-floater .sf-sep{width:1px;height:16px;background:var(--border);margin:0 2px;flex-shrink:0}
|
|
580
673
|
|
|
581
674
|
/* \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 */
|
|
582
|
-
.dt-tree{
|
|
675
|
+
.dt-tree{user-select:none}
|
|
583
676
|
.dt-row{
|
|
584
|
-
|
|
585
|
-
|
|
677
|
+
width: 100%;
|
|
678
|
+
display: flex;
|
|
679
|
+
align-items: center;
|
|
680
|
+
gap: 2px;
|
|
681
|
+
min-height: 26px;
|
|
682
|
+
padding: 10px 8px 10px 4px;
|
|
683
|
+
cursor: pointer;
|
|
684
|
+
color: var(--text-2);
|
|
685
|
+
position: relative;
|
|
586
686
|
}
|
|
587
687
|
.dt-row:hover{background:var(--bg-hover);color:var(--text)}
|
|
588
|
-
.dt-row.dt-selected{background
|
|
688
|
+
.dt-row.dt-selected{position:relative;background:var(--bg-hover);}
|
|
689
|
+
.dt-row.dt-selected::before, .dt-row:hover::before{
|
|
690
|
+
display: block;
|
|
691
|
+
content: '';
|
|
692
|
+
position: absolute;
|
|
693
|
+
top: 0;
|
|
694
|
+
left: 0px;
|
|
695
|
+
height: 100%;
|
|
696
|
+
width: 2px;
|
|
697
|
+
background: #262626;
|
|
698
|
+
}
|
|
699
|
+
.dt-row.dt-selected .dt-lbl .dt-tag{
|
|
700
|
+
background: var(--bg-primary-default, #262626)!important;
|
|
701
|
+
color: var(--text-primary-default, #FFF)!important;
|
|
702
|
+
}
|
|
589
703
|
.dt-chev{
|
|
590
704
|
width:16px;height:16px;flex-shrink:0;border:none;background:transparent;
|
|
591
705
|
cursor:pointer;color:var(--text-3);display:flex;align-items:center;justify-content:center;
|
|
@@ -594,22 +708,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
|
|
|
594
708
|
.dt-chev:hover{color:var(--text)}
|
|
595
709
|
.dt-chev.dt-spacer{visibility:hidden;pointer-events:none}
|
|
596
710
|
.dt-ico{width:16px;flex-shrink:0;text-align:center;color:var(--text-3);font-size:12px}
|
|
597
|
-
.dt-lbl{
|
|
711
|
+
.dt-lbl{
|
|
712
|
+
flex: 1;
|
|
713
|
+
overflow: hidden;
|
|
714
|
+
text-overflow: ellipsis;
|
|
715
|
+
white-space: nowrap;
|
|
716
|
+
color: var(--content-strong, #171717);
|
|
717
|
+
font-family: "JetBrains Mono";
|
|
718
|
+
}
|
|
598
719
|
.dt-muted{padding:16px 12px;text-align:center;color:var(--text-3);font-size:11px;line-height:1.4}
|
|
599
720
|
#section-components-panel{
|
|
600
721
|
max-height: 50%;
|
|
601
722
|
overflow-y: auto;
|
|
723
|
+
flex-shrink: 0;
|
|
724
|
+
display: flex;
|
|
725
|
+
flex-direction: column;
|
|
602
726
|
}
|
|
727
|
+
#section-components-panel .lp-body.collapsed{display:none}
|
|
603
728
|
/* \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 */
|
|
604
729
|
#right-panel{
|
|
605
|
-
width:
|
|
730
|
+
width:288px;
|
|
731
|
+
border-left: 1px solid var(--border-default, #E5E5E5);
|
|
732
|
+
background: var(--cu-Background-Main, #FFF);
|
|
606
733
|
display:flex;flex-direction:column;flex-shrink:0;overflow:hidden
|
|
607
734
|
}
|
|
608
735
|
|
|
609
736
|
/* \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 */
|
|
610
737
|
#breadcrumb{
|
|
738
|
+
display:none;
|
|
611
739
|
height:26px;background:var(--bg);border-top:1px solid var(--border);
|
|
612
|
-
|
|
740
|
+
align-items:center;padding:0 12px;font-size:11px;
|
|
613
741
|
color:var(--text-3);flex-shrink:0;gap:5px;overflow:hidden
|
|
614
742
|
}
|
|
615
743
|
|
|
@@ -622,9 +750,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
|
|
|
622
750
|
|
|
623
751
|
/* \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 */
|
|
624
752
|
#device-frame{
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
753
|
+
width: 100%;
|
|
754
|
+
min-height: 100%;
|
|
755
|
+
display: flex;
|
|
756
|
+
align-items: center;
|
|
757
|
+
transform-origin: top left;
|
|
758
|
+
transition: max-width .3s ease,width .2s ease,height .2s ease;
|
|
759
|
+
flex-shrink: 0;
|
|
628
760
|
}
|
|
629
761
|
#device-frame.desktop{
|
|
630
762
|
max-width:1440px;
|
|
@@ -675,33 +807,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
|
|
|
675
807
|
}
|
|
676
808
|
|
|
677
809
|
/* \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 */
|
|
678
|
-
.lp-sec{border-bottom:1px solid var(--border);flex-shrink:0;padding: 24px;}
|
|
810
|
+
.lp-sec{border-bottom:1px solid var(--border);flex-shrink:0;padding: 24px 16px;}
|
|
679
811
|
.lp-sec-no-border{border-bottom:none!important}
|
|
680
812
|
.lp-sec-hd{
|
|
681
813
|
margin-bottom: 12px;
|
|
682
814
|
font-size:14px;font-weight:600;
|
|
815
|
+
line-height: 20px;
|
|
683
816
|
color:#404040;display:flex;align-items:center;justify-content:space-between;gap:5px
|
|
684
817
|
}
|
|
685
818
|
.lp-sec-hd-left{display:flex;align-items:center;gap:5px}
|
|
686
819
|
#active-var-label{display:none;color:var(--accent-txt);font-size:10px;font-weight:500}
|
|
687
820
|
.lp-info-icon{font-size:11px;color:var(--text-3);cursor:default;opacity:.7}
|
|
688
821
|
.lp-add-btn{
|
|
689
|
-
|
|
690
|
-
|
|
822
|
+
background: none;
|
|
823
|
+
border: none;
|
|
824
|
+
cursor: pointer;
|
|
825
|
+
padding: 2px 5px;
|
|
826
|
+
border-radius: 4px;
|
|
827
|
+
transition: all .12s;
|
|
828
|
+
flex-shrink: 0;
|
|
829
|
+
color: var(--content-default, #404040);
|
|
830
|
+
text-align: center;
|
|
831
|
+
font-family: Inter;
|
|
832
|
+
font-size: 12px;
|
|
833
|
+
font-style: normal;
|
|
834
|
+
font-weight: 500;
|
|
835
|
+
line-height: 14px;
|
|
691
836
|
}
|
|
692
|
-
.lp-add-btn:hover{
|
|
837
|
+
.lp-add-btn:hover{opacity:0.8}
|
|
693
838
|
|
|
694
839
|
/* \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 */
|
|
695
840
|
#variation-tabs{display:flex;flex-direction:column; gap:8px;}
|
|
696
841
|
.var-tab{
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
842
|
+
border-radius: var(--radius-md, 6px);
|
|
843
|
+
border:1px solid transparent;
|
|
844
|
+
background: var(--bg-interactive-default, #FFF);
|
|
845
|
+
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);
|
|
846
|
+
cursor:pointer;font-size:15px;font-weight:500;padding:7px 10px;transition:background .12s,color .12s,border-color .12s;
|
|
701
847
|
width:100%;text-align:left;display:flex;align-items:center;gap:8px;
|
|
848
|
+
line-height: 16px;
|
|
702
849
|
}
|
|
703
850
|
.var-tab:hover{background:var(--bg-hover);color:var(--text)}
|
|
704
|
-
.var-tab.active{
|
|
851
|
+
button.var-tab.active{
|
|
852
|
+
color:var(--accent-txt);
|
|
853
|
+
border-color:var(--var-tab-color, transparent);
|
|
854
|
+
}
|
|
705
855
|
.var-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}
|
|
706
856
|
.var-add-row{
|
|
707
857
|
display:none!important;
|
|
@@ -715,51 +865,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
|
|
|
715
865
|
.var-add-row:hover{color:var(--accent-txt)}
|
|
716
866
|
|
|
717
867
|
/* \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 */
|
|
868
|
+
.lp-search-container{margin-bottom:8px}
|
|
869
|
+
.lp-search-field{
|
|
870
|
+
position:relative;
|
|
871
|
+
display:flex;
|
|
872
|
+
align-items:center;
|
|
873
|
+
width:100%;
|
|
874
|
+
}
|
|
875
|
+
.lp-search-icon{
|
|
876
|
+
position:absolute;
|
|
877
|
+
left:12px;
|
|
878
|
+
top:50%;
|
|
879
|
+
transform:translateY(-50%);
|
|
880
|
+
display:flex;
|
|
881
|
+
align-items:center;
|
|
882
|
+
justify-content:center;
|
|
883
|
+
width:16px;
|
|
884
|
+
height:16px;
|
|
885
|
+
pointer-events:none;
|
|
886
|
+
color:var(--base-sub-2,#B5B5B5);
|
|
887
|
+
flex-shrink:0;
|
|
888
|
+
}
|
|
889
|
+
.lp-search-icon svg{display:block;width:16px;height:16px}
|
|
890
|
+
.lp-search-icon svg path{stroke:currentColor}
|
|
718
891
|
#comp-search{
|
|
719
|
-
|
|
720
|
-
color:var(--text);
|
|
892
|
+
border:1px solid var(--border);
|
|
893
|
+
color:var(--text);
|
|
894
|
+
font-size:12px;
|
|
895
|
+
padding:9px 12px 9px 36px;
|
|
896
|
+
width:100%;
|
|
897
|
+
outline:none;
|
|
898
|
+
border-radius:6px;
|
|
899
|
+
background:var(--Greyscale-0,#FFF);
|
|
900
|
+
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);
|
|
721
901
|
}
|
|
722
|
-
#comp-search::placeholder{
|
|
723
|
-
|
|
724
|
-
|
|
902
|
+
#comp-search::placeholder{
|
|
903
|
+
color:var(--base-sub-2,#B5B5B5);
|
|
904
|
+
font-size:var(--font-size-sm,14px);
|
|
905
|
+
font-style:normal;
|
|
906
|
+
font-weight:500;
|
|
907
|
+
}
|
|
908
|
+
#comp-search:focus{border-color:#000;}
|
|
725
909
|
/* \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 */
|
|
726
|
-
.lp-tabs
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
910
|
+
.lp-tabs-container{
|
|
911
|
+
display:flex;
|
|
912
|
+
align-items:center;
|
|
913
|
+
justify-content:space-between;
|
|
730
914
|
}
|
|
731
|
-
.lp-
|
|
732
|
-
|
|
733
|
-
|
|
915
|
+
.lp-tabs{
|
|
916
|
+
width: 100%;
|
|
917
|
+
padding: 4px 10px;
|
|
918
|
+
flex: 1;
|
|
734
919
|
display: flex;
|
|
735
|
-
|
|
920
|
+
border-radius: 6px;
|
|
921
|
+
background: var(--base-soft-2,#F0F0F0);
|
|
922
|
+
padding: 4px 6px;
|
|
923
|
+
flex-shrink: 0;
|
|
924
|
+
gap: 6px;
|
|
925
|
+
align-items: center;
|
|
926
|
+
white-space: nowrap;
|
|
927
|
+
}
|
|
928
|
+
.lp-tab{
|
|
929
|
+
flex: 1;
|
|
930
|
+
text-align: center;
|
|
931
|
+
color: #404040;
|
|
932
|
+
white-space: nowrap;
|
|
933
|
+
cursor: pointer;
|
|
934
|
+
transition: all .15s;
|
|
935
|
+
line-height: 1.15;
|
|
936
|
+
font-size: var(--font-size-sm,14px);
|
|
937
|
+
font-weight: 500;
|
|
938
|
+
padding:4px 10px;
|
|
939
|
+
}
|
|
940
|
+
.section-components-tabs-container{
|
|
941
|
+
display: flex;
|
|
736
942
|
align-items: center;
|
|
737
|
-
justify-content:
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
943
|
+
justify-content: space-between;
|
|
944
|
+
flex-shrink: 0;
|
|
945
|
+
padding: 12px 16px;
|
|
946
|
+
border-bottom: 1px solid #F5F5F5;
|
|
947
|
+
}
|
|
948
|
+
.section-components-tabs-container .lp-tabs{
|
|
949
|
+
flex:1;
|
|
741
950
|
}
|
|
951
|
+
.lp-tab.close-section-components-panel{
|
|
952
|
+
flex:0 0 auto;
|
|
953
|
+
flex-shrink:0;
|
|
954
|
+
display:flex;
|
|
955
|
+
align-items:center;
|
|
956
|
+
justify-content:center;
|
|
957
|
+
width:24px;
|
|
958
|
+
height:24px;
|
|
959
|
+
padding:0;
|
|
960
|
+
background:none;
|
|
961
|
+
border-radius:4px;
|
|
962
|
+
color:var(--content-default,#404040);
|
|
963
|
+
line-height:1;
|
|
964
|
+
white-space:nowrap;
|
|
965
|
+
}
|
|
966
|
+
.lp-tab.close-section-components-panel i{
|
|
967
|
+
font-size:14px;
|
|
968
|
+
line-height:1;
|
|
969
|
+
transition:transform .15s;
|
|
970
|
+
}
|
|
971
|
+
.lp-tab.close-section-components-panel.collapsed i{transform:rotate(-180deg)}
|
|
742
972
|
.lp-tab:hover{color:var(--text-2)}
|
|
743
|
-
.lp-tab.active{
|
|
973
|
+
.lp-tab.active{
|
|
974
|
+
border-radius:4px;
|
|
975
|
+
background:var(--bg-interactive-default,#FFF);
|
|
976
|
+
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);
|
|
977
|
+
}
|
|
978
|
+
.lp-tab.close-section-components-panel:hover{opacity:.8;color:var(--text-2)}
|
|
979
|
+
.lp-tab.close-section-components-panel.active{
|
|
980
|
+
background:none;
|
|
981
|
+
box-shadow:none;
|
|
982
|
+
border-radius:4px;
|
|
983
|
+
}
|
|
744
984
|
.future-hidden{display:none!important}
|
|
745
985
|
|
|
746
986
|
/* \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 */
|
|
987
|
+
.lp-body #tab-dom-tree, .lp-body #tab-elements{
|
|
988
|
+
padding-top:4px;
|
|
989
|
+
}
|
|
990
|
+
.lp-body #tab-elements .dt-lbl{
|
|
991
|
+
font-size: 12px;
|
|
992
|
+
font-style: normal;
|
|
993
|
+
font-weight: 500;
|
|
994
|
+
line-height: 14px;
|
|
995
|
+
letter-spacing: -0.1px;
|
|
996
|
+
}
|
|
997
|
+
.lp-body #tab-elements #elements-root > .dt-row{
|
|
998
|
+
padding-left: 16px!important;
|
|
999
|
+
}
|
|
1000
|
+
.lp-body #dom-tree-root .dt-lbl{
|
|
1001
|
+
color: var(--content-subtle, #737373);
|
|
1002
|
+
font-style: normal;
|
|
1003
|
+
font-weight: 400;
|
|
1004
|
+
line-height: var(--font-leading-3, 12px); /* 100% */
|
|
1005
|
+
letter-spacing: -0.1px;
|
|
1006
|
+
}
|
|
1007
|
+
.lp-body #dom-tree-root .dt-lbl .dt-tag{
|
|
1008
|
+
color: var(--content-strong, #171717);
|
|
1009
|
+
font-family: "JetBrains Mono";
|
|
1010
|
+
font-size: 12px;
|
|
1011
|
+
font-style: normal;
|
|
1012
|
+
font-weight: 500;
|
|
1013
|
+
line-height: 14px;
|
|
1014
|
+
letter-spacing: -0.1px;
|
|
1015
|
+
border-radius: 4px;
|
|
1016
|
+
background: var(--bg-surface-subtle, #F5F5F5);
|
|
1017
|
+
padding:3px 6px;
|
|
1018
|
+
display:inline-block;
|
|
1019
|
+
margin-right:4px;
|
|
1020
|
+
}
|
|
1021
|
+
.lp-body #tab-elements .dt-row .dt-chev.dt-spacer{display:none;}
|
|
1022
|
+
.lp-body #tab-dom-tree .dt-row .dt-ico{display:none;}
|
|
747
1023
|
.lp-body, .section-components-body{flex:1;overflow-y:auto}
|
|
748
1024
|
.lp-body::-webkit-scrollbar, .section-components-body::-webkit-scrollbar{width:3px}
|
|
749
1025
|
.lp-body::-webkit-scrollbar-thumb, .section-components-body::-webkit-scrollbar-thumb{background:#cbd5e1;border-radius:2px}
|
|
750
1026
|
.tab-pane, .section-components-tab-pane{display:none}.tab-pane.active, .section-components-tab-pane.active{display:block}
|
|
751
1027
|
|
|
752
1028
|
/* \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 */
|
|
753
|
-
.cg-hdr{padding:
|
|
754
|
-
|
|
1029
|
+
.cg-hdr{ padding: 12px 12px;
|
|
1030
|
+
text-transform: uppercase;
|
|
1031
|
+
letter-spacing: .06em;
|
|
1032
|
+
color: var(--content-subtle, #737373);
|
|
1033
|
+
font-family: Inter;
|
|
1034
|
+
font-size: 12px;
|
|
1035
|
+
font-weight: 600;
|
|
1036
|
+
line-height: normal;
|
|
1037
|
+
}
|
|
1038
|
+
.cg-grid{ display: grid;
|
|
1039
|
+
grid-template-columns: 1fr 1fr 1fr;
|
|
1040
|
+
padding: 0 12px 12px;
|
|
1041
|
+
column-gap: 8px;
|
|
1042
|
+
row-gap: 12px;}
|
|
755
1043
|
.cg-item{
|
|
756
|
-
|
|
757
|
-
|
|
1044
|
+
background: #fff;
|
|
1045
|
+
cursor: pointer;
|
|
1046
|
+
padding: 15px 11px;
|
|
1047
|
+
text-align: center;
|
|
1048
|
+
transition: all .15s;
|
|
1049
|
+
color: var(--text-2);
|
|
1050
|
+
user-select: none;
|
|
1051
|
+
border-radius: 6px;
|
|
1052
|
+
border: 1px solid var(--border-default, #E5E5E5);
|
|
758
1053
|
}
|
|
759
1054
|
.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)}
|
|
760
1055
|
.cg-item:active{transform:translateY(0);box-shadow:none}
|
|
761
|
-
.cg-icon{
|
|
762
|
-
|
|
1056
|
+
.cg-icon{ margin-bottom: 6px;
|
|
1057
|
+
color: var(--content-default, #404040);
|
|
1058
|
+
font-family: Inter;
|
|
1059
|
+
font-size: var(--font-size-sm, 14px);
|
|
1060
|
+
font-style: normal;
|
|
1061
|
+
font-weight: 500;
|
|
1062
|
+
line-height: var(--font-leading-4, 16px);}
|
|
1063
|
+
.cg-name{ color: var(--content-subtle, #737373);
|
|
1064
|
+
font-family: Inter;
|
|
1065
|
+
font-size: var(--font-size-xs, 12px);
|
|
1066
|
+
font-style: normal;
|
|
1067
|
+
font-weight: 400;
|
|
1068
|
+
line-height: var(--font-leading-3, 12px);}
|
|
763
1069
|
|
|
764
1070
|
/* \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 */
|
|
765
1071
|
.sec-item{
|
|
@@ -768,8 +1074,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
|
|
|
768
1074
|
}
|
|
769
1075
|
.sec-item:hover{border-color:var(--accent);transform:translateY(-1px);box-shadow:0 4px 12px rgba(99,102,241,.12)}
|
|
770
1076
|
.sec-thumb{
|
|
771
|
-
background:var(--bg-sub);height:
|
|
772
|
-
justify-content:center;font-size:22px;border-bottom:1px solid var(--border)
|
|
1077
|
+
background:var(--bg-sub);height:72px;display:flex;align-items:center;
|
|
1078
|
+
justify-content:center;font-size:22px;border-bottom:1px solid var(--border);
|
|
1079
|
+
overflow:hidden;
|
|
1080
|
+
}
|
|
1081
|
+
.sec-thumb img{
|
|
1082
|
+
width:100%;height:100%;object-fit:cover;object-position:top center;display:block;
|
|
773
1083
|
}
|
|
774
1084
|
.sec-info{padding:7px 9px}
|
|
775
1085
|
.sec-name{font-size:11px;font-weight:600;color:var(--text)}
|
|
@@ -785,9 +1095,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
|
|
|
785
1095
|
#no-sel .ns-icon{font-size:32px;margin-bottom:10px;opacity:.4}
|
|
786
1096
|
|
|
787
1097
|
/* \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 */
|
|
788
|
-
#el-info{padding:8px 12px;border-bottom:1px solid var(--border);background:var(--bg-sub);flex-shrink:0}
|
|
789
|
-
#el-info-tag{font-size:10px;font-weight:700;color:var(--text-3);text-transform:uppercase;letter-spacing:.05em;font-family:
|
|
790
|
-
#el-info-sel{font-size:10px;color:var(--accent-txt);font-family:
|
|
1098
|
+
#el-info{padding:8px 12px;border-bottom:1px solid var(--border);background:var(--bg-sub);flex-shrink:0;display:none;}
|
|
1099
|
+
#el-info-tag{font-size:10px;font-weight:700;color:var(--text-3);text-transform:uppercase;letter-spacing:.05em;font-family:var(--font-mono)}
|
|
1100
|
+
#el-info-sel{font-size:10px;color:var(--accent-txt);font-family:var(--font-mono);margin-top:2px;word-break:break-all;opacity:.8}
|
|
791
1101
|
|
|
792
1102
|
/* \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 */
|
|
793
1103
|
.acc-section{border-bottom:1px solid var(--border-sub)}
|
|
@@ -842,7 +1152,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
|
|
|
842
1152
|
.custom-css-close:hover{background:var(--bg-hover);color:var(--text)}
|
|
843
1153
|
#custom-css-modal-textarea{
|
|
844
1154
|
width:100%;min-height:360px;max-height:58vh;resize:vertical;border:none;outline:none;
|
|
845
|
-
font-family:
|
|
1155
|
+
font-family:var(--font-mono);
|
|
846
1156
|
font-size:12px;line-height:1.5;padding:12px;background:#0b1220;color:#e2e8f0
|
|
847
1157
|
}
|
|
848
1158
|
.custom-css-actions{
|
|
@@ -885,7 +1195,7 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
885
1195
|
.adv-section{padding:10px}
|
|
886
1196
|
.adv-row{margin-bottom:8px}
|
|
887
1197
|
.adv-key{font-size:10px;color:var(--text-3);margin-bottom:3px;font-weight:700;text-transform:uppercase;letter-spacing:.05em}
|
|
888
|
-
.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:
|
|
1198
|
+
.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)}
|
|
889
1199
|
|
|
890
1200
|
/* \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 */
|
|
891
1201
|
/* Selection chrome is injected into the iframe (see injectIframeSelectionStyles); rules here are fallback only */
|
|
@@ -919,14 +1229,37 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
919
1229
|
.img-add:hover{border-color:var(--accent);color:var(--accent-txt);background:var(--accent-bg)}
|
|
920
1230
|
|
|
921
1231
|
/* \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 */
|
|
922
|
-
#main-tabs{
|
|
1232
|
+
#main-tabs{
|
|
1233
|
+
display:flex;
|
|
1234
|
+
align-items:center;
|
|
1235
|
+
gap:6px;
|
|
1236
|
+
margin:12px 16px 8px;
|
|
1237
|
+
padding:4px 6px;
|
|
1238
|
+
border-radius:6px;
|
|
1239
|
+
background:var(--base-soft-2,#F0F0F0);
|
|
1240
|
+
flex-shrink:0;
|
|
1241
|
+
}
|
|
923
1242
|
.main-tab{
|
|
924
|
-
flex:1;
|
|
925
|
-
|
|
926
|
-
|
|
1243
|
+
flex:1;
|
|
1244
|
+
padding:4px 10px;
|
|
1245
|
+
text-align:center;
|
|
1246
|
+
font-size:var(--font-size-sm,14px);
|
|
1247
|
+
font-weight:500;
|
|
1248
|
+
line-height:1.15;
|
|
1249
|
+
color:#404040;
|
|
1250
|
+
white-space:nowrap;
|
|
1251
|
+
cursor:pointer;
|
|
1252
|
+
border:none;
|
|
1253
|
+
background:transparent;
|
|
1254
|
+
transition:all .15s;
|
|
1255
|
+
font-family:inherit;
|
|
927
1256
|
}
|
|
928
1257
|
.main-tab:hover{color:var(--text-2)}
|
|
929
|
-
.main-tab.active{
|
|
1258
|
+
.main-tab.active{
|
|
1259
|
+
border-radius:4px;
|
|
1260
|
+
background:var(--bg-interactive-default,#FFF);
|
|
1261
|
+
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);
|
|
1262
|
+
}
|
|
930
1263
|
.rp-pane{flex:1;overflow-y:auto;overflow-x:hidden;min-width:0;display:none}
|
|
931
1264
|
.rp-pane.active{display:block}
|
|
932
1265
|
|
|
@@ -935,13 +1268,13 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
935
1268
|
.states-empty i{font-size:30px;display:block;margin-bottom:10px;opacity:.3}
|
|
936
1269
|
.state-group{border-bottom:1px solid var(--border-sub)}
|
|
937
1270
|
.state-group-sel{
|
|
938
|
-
padding:8px 12px 3px;font-size:10px;font-family:
|
|
1271
|
+
padding:8px 12px 3px;font-size:10px;font-family:var(--font-mono);
|
|
939
1272
|
color:var(--text-3);font-weight:700;word-break:break-all;letter-spacing:-.01em
|
|
940
1273
|
}
|
|
941
1274
|
.state-item{display:flex;align-items:center;padding:4px 10px 4px 18px;gap:6px}
|
|
942
1275
|
.state-item-label{flex:1;font-size:11px;color:var(--text-2)}
|
|
943
1276
|
.state-item-val{
|
|
944
|
-
font-size:10px;color:var(--accent-txt);font-family:
|
|
1277
|
+
font-size:10px;color:var(--accent-txt);font-family:var(--font-mono);
|
|
945
1278
|
max-width:68px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
|
|
946
1279
|
background:var(--accent-bg);padding:1px 5px;border-radius:3px
|
|
947
1280
|
}
|
|
@@ -1069,7 +1402,17 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1069
1402
|
<div id="dev-more-menu" class="tb-dev-menu" aria-hidden="true">
|
|
1070
1403
|
<div class="row row-zoom">
|
|
1071
1404
|
<label for="dev-zoom-level">Zoom</label>
|
|
1072
|
-
<
|
|
1405
|
+
<div class="zoom-controls">
|
|
1406
|
+
<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">
|
|
1407
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true">
|
|
1408
|
+
<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"/>
|
|
1409
|
+
<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"/>
|
|
1410
|
+
<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"/>
|
|
1411
|
+
<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"/>
|
|
1412
|
+
</svg>
|
|
1413
|
+
</button>
|
|
1414
|
+
<input id="dev-zoom-level" type="number" min="25" max="200" step="5" value="100" />
|
|
1415
|
+
</div>
|
|
1073
1416
|
</div>
|
|
1074
1417
|
<div class="row row-split row-width height-width-row">
|
|
1075
1418
|
<div class="row" style="margin:0">
|
|
@@ -1094,9 +1437,6 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1094
1437
|
<button type="button" class="vp-preset-btn" data-preset="iphone-7">iPhone 7</button>
|
|
1095
1438
|
<button type="button" class="vp-preset-btn" data-preset="responsive">Responsive</button>
|
|
1096
1439
|
</div>
|
|
1097
|
-
<div class="ft">
|
|
1098
|
-
<button type="button" class="apply-btn" id="dev-apply-btn">Apply</button>
|
|
1099
|
-
</div>
|
|
1100
1440
|
</div>
|
|
1101
1441
|
</div>
|
|
1102
1442
|
<button class="tb-dk-btn" id="btn-undo" title="Undo (\u2318Z)"><i class="bi bi-arrow-counterclockwise"></i></button>
|
|
@@ -1124,15 +1464,16 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1124
1464
|
<span class="tb-save-txt"></span>
|
|
1125
1465
|
<span id="tb-save-time" class="tb-save-time"></span>
|
|
1126
1466
|
</div>
|
|
1467
|
+
<button class="tb-fin-btn" id="btn-save">Save Changes</button>
|
|
1127
1468
|
<div class="tb-dev-3btns">
|
|
1128
1469
|
<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>
|
|
1129
|
-
<button class="tb-dk-btn" id="btn-mode-nav" onclick="setMode('navigate')" title="Navigate mode \u2014 interact with page normally"><i class="bi bi-
|
|
1470
|
+
<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>
|
|
1130
1471
|
<button class="tb-dk-btn" title="Comments"><i class="bi bi-chat-dots"></i></button>
|
|
1131
1472
|
</div>
|
|
1132
|
-
<button class="tb-sim-btn" id="btn-simulate" onclick="simulateExperiment()"
|
|
1133
|
-
|
|
1473
|
+
<button class="tb-sim-btn" id="btn-simulate" onclick="simulateExperiment()">See Preview</button>
|
|
1474
|
+
|
|
1134
1475
|
<!-- btn-close: kept for JS event listener -->
|
|
1135
|
-
<button class="tb-fin-btn" id="btn-close">
|
|
1476
|
+
<button class="tb-fin-btn" id="btn-close">Exit Editor</button>
|
|
1136
1477
|
</div>
|
|
1137
1478
|
|
|
1138
1479
|
<!-- url-bar: hidden, kept for JS compatibility -->
|
|
@@ -1170,22 +1511,28 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1170
1511
|
|
|
1171
1512
|
<!-- Elements -->
|
|
1172
1513
|
<div class="lp-sec lp-sec-no-border">
|
|
1173
|
-
<div class="lp-sec-hd">
|
|
1174
|
-
<span class="lp-sec-hd-left">Elements <i style="display:none" class="bi bi-info-circle lp-info-icon" title="Page elements"></i></span>
|
|
1175
|
-
<button class="lp-add-btn" id="btn-add-element" title="Add element">+ Add</button>
|
|
1176
|
-
</div>
|
|
1177
|
-
|
|
1178
1514
|
<!-- Search (hidden, kept for JS) -->
|
|
1179
|
-
<div>
|
|
1180
|
-
<
|
|
1515
|
+
<div class="lp-search-container">
|
|
1516
|
+
<div class="lp-search-field">
|
|
1517
|
+
<span class="lp-search-icon" aria-hidden="true">
|
|
1518
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
|
|
1519
|
+
<path d="M11.333 11.3333L13.9997 13.9999" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
|
1520
|
+
<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"/>
|
|
1521
|
+
</svg>
|
|
1522
|
+
</span>
|
|
1523
|
+
<input type="search" id="comp-search" placeholder="Search" autocomplete="off">
|
|
1524
|
+
</div>
|
|
1181
1525
|
</div>
|
|
1182
1526
|
|
|
1183
1527
|
|
|
1184
1528
|
<!-- Tabs (hidden, kept for JS) -->
|
|
1185
|
-
<div class="lp-tabs"
|
|
1186
|
-
<div class="lp-
|
|
1529
|
+
<div class="lp-tabs-container">
|
|
1530
|
+
<div class="lp-tabs">
|
|
1531
|
+
<div class="lp-tab active" onclick="switchLeftTab('elements')">Elements</div>
|
|
1187
1532
|
<div class="lp-tab" onclick="switchLeftTab('dom-tree')">DOM Tree</div>
|
|
1188
1533
|
</div>
|
|
1534
|
+
<button class="lp-add-btn" id="btn-add-element" title="Add element">+ Add</button>
|
|
1535
|
+
</div>
|
|
1189
1536
|
|
|
1190
1537
|
</div>
|
|
1191
1538
|
|
|
@@ -1214,11 +1561,11 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1214
1561
|
|
|
1215
1562
|
<!-- Floating toolbar for selected element (positioned over iframe) -->
|
|
1216
1563
|
<div id="selection-floater" aria-label="Selection actions">
|
|
1564
|
+
<button type="button" class="sf-btn" id="sf-add" title="Add element"><i class="bi bi-plus-lg"></i></button>
|
|
1565
|
+
<span class="sf-sep"></span>
|
|
1217
1566
|
<button type="button" class="sf-btn" id="sf-move-up" title="Move up"><i class="bi bi-arrow-up"></i></button>
|
|
1218
1567
|
<button type="button" class="sf-btn" id="sf-move-down" title="Move down"><i class="bi bi-arrow-down"></i></button>
|
|
1219
1568
|
<span class="sf-sep"></span>
|
|
1220
|
-
<button type="button" class="sf-btn" id="sf-resize" disabled title="Resize (coming soon)"><i class="bi bi-arrows-angle-expand"></i></button>
|
|
1221
|
-
<button type="button" class="sf-btn" id="sf-rotate" disabled title="Rotate (coming soon)"><i class="bi bi-arrow-repeat"></i></button>
|
|
1222
1569
|
<button type="button" class="sf-btn" id="sf-dup" title="Duplicate"><i class="bi bi-files"></i></button>
|
|
1223
1570
|
<button type="button" class="sf-btn" id="sf-hide" title="Hide"><i class="bi bi-eye-slash"></i></button>
|
|
1224
1571
|
<button type="button" class="sf-btn" id="sf-del" title="Delete"><i class="bi bi-trash"></i></button>
|
|
@@ -1242,14 +1589,16 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1242
1589
|
|
|
1243
1590
|
<!-- Right panel -->
|
|
1244
1591
|
<div id="right-panel">
|
|
1245
|
-
<div id="section-components-panel"
|
|
1592
|
+
<div id="section-components-panel">
|
|
1246
1593
|
<!-- Left-tab controls moved here -->
|
|
1247
|
-
<div class="section-components-tabs">
|
|
1248
|
-
<div class="lp-
|
|
1249
|
-
|
|
1250
|
-
|
|
1594
|
+
<div class="lp-tabs-container section-components-tabs-container">
|
|
1595
|
+
<div class="lp-tabs">
|
|
1596
|
+
<div class="lp-tab" onclick="switchSectionComponentsTab('components')">Components</div>
|
|
1597
|
+
<div class="lp-tab" onclick="switchSectionComponentsTab('sections')">Sections</div>
|
|
1598
|
+
</div>
|
|
1599
|
+
<div class="lp-tab close-section-components-panel collapsed" onclick="toggleSectionComponentsBody()" title="Toggle components list"><i class="bi bi-chevron-down"></i></div>
|
|
1251
1600
|
</div>
|
|
1252
|
-
<div class="lp-body">
|
|
1601
|
+
<div class="lp-body collapsed">
|
|
1253
1602
|
<div id="tab-components" class="tab-pane"></div>
|
|
1254
1603
|
<div id="tab-sections" class="tab-pane"></div>
|
|
1255
1604
|
</div>
|
|
@@ -1262,7 +1611,7 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1262
1611
|
<!-- \u2500\u2500 3 main tabs \u2500\u2500 -->
|
|
1263
1612
|
<div id="main-tabs">
|
|
1264
1613
|
<button class="main-tab active" onclick="switchMainTab('design')">Design</button>
|
|
1265
|
-
<button class="main-tab" onclick="switchMainTab('states')">States</button>
|
|
1614
|
+
<button class="main-tab" style="display:none" onclick="switchMainTab('states')">States</button>
|
|
1266
1615
|
<button class="main-tab" onclick="switchMainTab('history')">History</button>
|
|
1267
1616
|
</div>
|
|
1268
1617
|
|
|
@@ -1452,26 +1801,35 @@ if (window.Vvveb && window.Vvveb.Components) {
|
|
|
1452
1801
|
|
|
1453
1802
|
// \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
|
|
1454
1803
|
var CRO_SECTIONS = ${sectionsJson};
|
|
1804
|
+
var CRO_SECTION_IMAGE_ROUTE = ${JSON.stringify(CRO_SECTION_IMAGE_ROUTE)};
|
|
1805
|
+
|
|
1806
|
+
function renderCroSectionThumb(sec) {
|
|
1807
|
+
if (sec && sec.image) {
|
|
1808
|
+
return '<img src="' + CRO_SECTION_IMAGE_ROUTE + sec.image + '" alt="' + esc(sec.name || '') + '" loading="lazy">';
|
|
1809
|
+
}
|
|
1810
|
+
return sec && sec.icon ? sec.icon : '\u{1F4E6}';
|
|
1811
|
+
}
|
|
1455
1812
|
|
|
1456
1813
|
var BASE_COMPONENTS = [
|
|
1457
|
-
{ name:'Heading', icon:'bi-type-h1', html:'<h2>Your Heading</h2>' },
|
|
1458
|
-
{ name:'Paragraph', icon:'bi-paragraph', html:'<p>Your text here. Click to edit.</p>' },
|
|
1459
|
-
{ name:'Image', icon:'bi-image', html:'<img src="https://placehold.co/600x300/1a1a2e/a78bfa?text=Image" alt="Image" style="max-width:100
|
|
1460
|
-
{ name:'Button', icon:'bi-hand-index', html:'<button
|
|
1461
|
-
{ name:'Link', icon:'bi-link-45deg', html:'<a href="#">Link text</a>' },
|
|
1462
|
-
{ name:'Divider', icon:'bi-dash-lg', html:'<hr>' },
|
|
1463
|
-
{ name:'List', icon:'bi-list-ul', html:'<ul><li>Item 1</li><li>Item 2</li><li>Item 3</li></ul>' },
|
|
1464
|
-
{ name:'Video', icon:'bi-play-circle', html:'<video controls style="max-width:100
|
|
1465
|
-
{ name:'
|
|
1466
|
-
{ name:'
|
|
1467
|
-
{ name:'
|
|
1468
|
-
{ name:'
|
|
1469
|
-
{ name:'
|
|
1470
|
-
{ name:'
|
|
1471
|
-
{ name:'
|
|
1472
|
-
{ name:'
|
|
1473
|
-
{ name:'
|
|
1474
|
-
{ name:'
|
|
1814
|
+
{ 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>' },
|
|
1815
|
+
{ 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>' },
|
|
1816
|
+
{ 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">' },
|
|
1817
|
+
{ 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>' },
|
|
1818
|
+
{ 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>' },
|
|
1819
|
+
{ name:'Divider', icon:'bi-dash-lg', defaultAccSection:'background', html:'<hr style="margin:16px 0;border:none;border-top:1px solid #e2e8f0">' },
|
|
1820
|
+
{ 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>' },
|
|
1821
|
+
{ 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>' },
|
|
1822
|
+
{ 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>' },
|
|
1823
|
+
{ 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>' },
|
|
1824
|
+
{ 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>' },
|
|
1825
|
+
{ 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">' },
|
|
1826
|
+
{ 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>' },
|
|
1827
|
+
{ 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>' },
|
|
1828
|
+
{ 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>' },
|
|
1829
|
+
{ 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>' },
|
|
1830
|
+
{ 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>' },
|
|
1831
|
+
{ 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>' },
|
|
1832
|
+
{ 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>' },
|
|
1475
1833
|
];
|
|
1476
1834
|
|
|
1477
1835
|
// \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
|
|
@@ -1625,7 +1983,7 @@ var leftPanelCollapsed = false;
|
|
|
1625
1983
|
var viewportPreset = 'desktop';
|
|
1626
1984
|
var viewportWidth = 1440;
|
|
1627
1985
|
var viewportHeight = 1024;
|
|
1628
|
-
var viewportZoom =
|
|
1986
|
+
var viewportZoom = null;
|
|
1629
1987
|
var selectedEl = null;
|
|
1630
1988
|
/** Stable selector fingerprint for resilient selection recovery after DOM churn. */
|
|
1631
1989
|
var selectedElFingerprint = '';
|
|
@@ -1645,6 +2003,7 @@ var iframeSyncRetryTimer = null;
|
|
|
1645
2003
|
var iframeSyncAttempts = 0;
|
|
1646
2004
|
var selectionScrollWin = null;
|
|
1647
2005
|
var selectionResizeBound = false;
|
|
2006
|
+
var selectionPanelScrollBound = false;
|
|
1648
2007
|
var clickAttachDoc = null;
|
|
1649
2008
|
var hoverAttachDoc = null;
|
|
1650
2009
|
var changeObserver = null;
|
|
@@ -1896,16 +2255,22 @@ function clampViewportNumber(v, fallback, min, max) {
|
|
|
1896
2255
|
|
|
1897
2256
|
function getViewportFitZoom() {
|
|
1898
2257
|
var panel = document.getElementById('iframe-panel');
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
2258
|
+
if (!panel || !viewportWidth || viewportWidth <= 0 || !viewportHeight || viewportHeight <= 0) return 1;
|
|
2259
|
+
var availW = Math.max(260, panel.clientWidth);
|
|
2260
|
+
var availH = Math.max(200, panel.clientHeight);
|
|
2261
|
+
return Math.min(1, availW / viewportWidth, availH / viewportHeight);
|
|
1902
2262
|
}
|
|
1903
2263
|
|
|
1904
2264
|
function getAppliedViewportZoom() {
|
|
1905
|
-
var
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
return Math.min(
|
|
2265
|
+
var fit = getViewportFitZoom();
|
|
2266
|
+
var z = viewportZoom != null ? Number(viewportZoom) : fit;
|
|
2267
|
+
if (!Number.isFinite(z) || z <= 0) z = fit;
|
|
2268
|
+
return Math.max(0.25, Math.min(2, z));
|
|
2269
|
+
}
|
|
2270
|
+
|
|
2271
|
+
function resetViewportZoomToFit() {
|
|
2272
|
+
viewportZoom = null;
|
|
2273
|
+
applyViewportFrame();
|
|
1909
2274
|
}
|
|
1910
2275
|
|
|
1911
2276
|
function updateViewportLabel() {
|
|
@@ -1926,20 +2291,28 @@ function syncViewportMenuControls() {
|
|
|
1926
2291
|
presetButtons[i].classList.toggle('active', key === viewportPreset);
|
|
1927
2292
|
}
|
|
1928
2293
|
}
|
|
1929
|
-
if (widthInp) widthInp.value = String(viewportWidth);
|
|
1930
|
-
if (heightInp) heightInp.value = String(viewportHeight);
|
|
2294
|
+
if (widthInp && document.activeElement !== widthInp) widthInp.value = String(viewportWidth);
|
|
2295
|
+
if (heightInp && document.activeElement !== heightInp) heightInp.value = String(viewportHeight);
|
|
1931
2296
|
if (zoomInp) zoomInp.value = String(Math.round(getAppliedViewportZoom() * 100));
|
|
1932
2297
|
}
|
|
1933
2298
|
|
|
1934
2299
|
function applyViewportFrame() {
|
|
1935
2300
|
var frame = document.getElementById('device-frame');
|
|
1936
2301
|
var iframe = document.getElementById('iframeId');
|
|
2302
|
+
var panel = document.getElementById('iframe-panel');
|
|
1937
2303
|
if (!frame) return;
|
|
1938
2304
|
frame.className = currentDevice;
|
|
1939
2305
|
frame.style.width = viewportWidth + 'px';
|
|
1940
2306
|
frame.style.height = viewportHeight + 'px';
|
|
1941
2307
|
frame.style.maxWidth = 'none';
|
|
1942
|
-
|
|
2308
|
+
var zoom = getAppliedViewportZoom();
|
|
2309
|
+
var fit = getViewportFitZoom();
|
|
2310
|
+
frame.style.zoom = String(zoom);
|
|
2311
|
+
if (panel) {
|
|
2312
|
+
var zoomedIn = zoom > fit + 0.001;
|
|
2313
|
+
panel.style.overflow = zoomedIn ? 'auto' : 'hidden';
|
|
2314
|
+
panel.style.alignItems = zoomedIn ? 'flex-start' : 'center';
|
|
2315
|
+
}
|
|
1943
2316
|
if (iframe) {
|
|
1944
2317
|
iframe.style.height = viewportHeight + 'px';
|
|
1945
2318
|
iframe.style.minHeight = viewportHeight + 'px';
|
|
@@ -1956,6 +2329,7 @@ function setViewportPreset(presetKey) {
|
|
|
1956
2329
|
viewportWidth = preset.width;
|
|
1957
2330
|
viewportHeight = preset.height;
|
|
1958
2331
|
currentDevice = preset.device || 'desktop';
|
|
2332
|
+
viewportZoom = null;
|
|
1959
2333
|
['desktop','tablet','mobile'].forEach(function(d) {
|
|
1960
2334
|
document.getElementById('dev-' + d).classList.toggle('active', d === currentDevice);
|
|
1961
2335
|
});
|
|
@@ -1968,20 +2342,26 @@ function setDevice(device) {
|
|
|
1968
2342
|
var preset = DEVICE_PRESETS[device] || DEVICE_PRESETS.desktop;
|
|
1969
2343
|
viewportWidth = preset.width;
|
|
1970
2344
|
viewportHeight = preset.height;
|
|
2345
|
+
viewportZoom = null;
|
|
1971
2346
|
['desktop','tablet','mobile'].forEach(function(d) {
|
|
1972
2347
|
document.getElementById('dev-' + d).classList.toggle('active', d === device);
|
|
1973
2348
|
});
|
|
1974
2349
|
applyViewportFrame();
|
|
1975
2350
|
}
|
|
1976
2351
|
|
|
1977
|
-
function setViewportCustomFromInputs() {
|
|
2352
|
+
function setViewportCustomFromInputs(opts) {
|
|
2353
|
+
opts = opts || {};
|
|
1978
2354
|
var widthInp = document.getElementById('dev-custom-width');
|
|
1979
2355
|
var heightInp = document.getElementById('dev-custom-height');
|
|
1980
|
-
var
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
2356
|
+
var rawW = widthInp ? widthInp.value : '';
|
|
2357
|
+
var rawH = heightInp ? heightInp.value : '';
|
|
2358
|
+
if (!opts.force) {
|
|
2359
|
+
if (widthInp && document.activeElement === widthInp && rawW === '') return;
|
|
2360
|
+
if (heightInp && document.activeElement === heightInp && rawH === '') return;
|
|
2361
|
+
}
|
|
2362
|
+
viewportWidth = clampViewportNumber(rawW, viewportWidth, 240, 3840);
|
|
2363
|
+
viewportHeight = clampViewportNumber(rawH, viewportHeight, 320, 3840);
|
|
2364
|
+
viewportZoom = null;
|
|
1985
2365
|
viewportPreset = 'custom';
|
|
1986
2366
|
currentDevice = viewportWidth <= 480 ? 'mobile' : (viewportWidth <= 1024 ? 'tablet' : 'desktop');
|
|
1987
2367
|
['desktop','tablet','mobile'].forEach(function(d) {
|
|
@@ -1990,6 +2370,22 @@ function setViewportCustomFromInputs() {
|
|
|
1990
2370
|
applyViewportFrame();
|
|
1991
2371
|
}
|
|
1992
2372
|
|
|
2373
|
+
var customViewportApplyTimer = null;
|
|
2374
|
+
function scheduleCustomViewportApply() {
|
|
2375
|
+
if (customViewportApplyTimer) clearTimeout(customViewportApplyTimer);
|
|
2376
|
+
customViewportApplyTimer = setTimeout(function() {
|
|
2377
|
+
customViewportApplyTimer = null;
|
|
2378
|
+
setViewportCustomFromInputs();
|
|
2379
|
+
}, 300);
|
|
2380
|
+
}
|
|
2381
|
+
function applyCustomViewportNow() {
|
|
2382
|
+
if (customViewportApplyTimer) {
|
|
2383
|
+
clearTimeout(customViewportApplyTimer);
|
|
2384
|
+
customViewportApplyTimer = null;
|
|
2385
|
+
}
|
|
2386
|
+
setViewportCustomFromInputs({ force: true });
|
|
2387
|
+
}
|
|
2388
|
+
|
|
1993
2389
|
function closeViewportMenu() {
|
|
1994
2390
|
var menu = document.getElementById('dev-more-menu');
|
|
1995
2391
|
if (!menu) return;
|
|
@@ -2010,8 +2406,10 @@ function bindViewportControls() {
|
|
|
2010
2406
|
var menu = document.getElementById('dev-more-menu');
|
|
2011
2407
|
var leftPanelToggleLabel = document.getElementById('left-panel-toggle-label');
|
|
2012
2408
|
var presetButtons = document.querySelectorAll('#dev-preset-list .vp-preset-btn');
|
|
2013
|
-
var
|
|
2409
|
+
var widthInp = document.getElementById('dev-custom-width');
|
|
2410
|
+
var heightInp = document.getElementById('dev-custom-height');
|
|
2014
2411
|
var zoomInp = document.getElementById('dev-zoom-level');
|
|
2412
|
+
var zoomFitBtn = document.getElementById('dev-zoom-fit-btn');
|
|
2015
2413
|
var viewportBtn = document.querySelector('.tb-viewport');
|
|
2016
2414
|
function updateLeftPanelToggleLabel() {
|
|
2017
2415
|
if (!leftPanelToggleLabel) return;
|
|
@@ -2041,11 +2439,21 @@ function bindViewportControls() {
|
|
|
2041
2439
|
e.stopPropagation();
|
|
2042
2440
|
toggleViewportMenu();
|
|
2043
2441
|
});
|
|
2044
|
-
if (
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2442
|
+
if (widthInp) {
|
|
2443
|
+
widthInp.addEventListener('input', scheduleCustomViewportApply);
|
|
2444
|
+
widthInp.addEventListener('change', applyCustomViewportNow);
|
|
2445
|
+
}
|
|
2446
|
+
if (heightInp) {
|
|
2447
|
+
heightInp.addEventListener('input', scheduleCustomViewportApply);
|
|
2448
|
+
heightInp.addEventListener('change', applyCustomViewportNow);
|
|
2449
|
+
}
|
|
2450
|
+
if (zoomFitBtn) {
|
|
2451
|
+
zoomFitBtn.addEventListener('click', function(e) {
|
|
2452
|
+
e.preventDefault();
|
|
2453
|
+
e.stopPropagation();
|
|
2454
|
+
resetViewportZoomToFit();
|
|
2455
|
+
});
|
|
2456
|
+
}
|
|
2049
2457
|
if (zoomInp) {
|
|
2050
2458
|
zoomInp.addEventListener('change', function() {
|
|
2051
2459
|
var z = clampViewportNumber(zoomInp.value, Math.round(getAppliedViewportZoom() * 100), 25, 200);
|
|
@@ -2080,7 +2488,7 @@ function bindViewportControls() {
|
|
|
2080
2488
|
function switchLeftTab(tab) {
|
|
2081
2489
|
if (tab !== 'elements' && tab !== 'dom-tree') return;
|
|
2082
2490
|
currentLeftTab = tab;
|
|
2083
|
-
var tabs = document.querySelectorAll('.lp-tabs .lp-tab');
|
|
2491
|
+
var tabs = document.querySelectorAll('#left-panel .lp-tabs .lp-tab');
|
|
2084
2492
|
for (var i = 0; i < tabs.length; i++) {
|
|
2085
2493
|
var oc = tabs[i].getAttribute('onclick') || '';
|
|
2086
2494
|
tabs[i].classList.toggle('active', oc.indexOf("switchLeftTab('" + tab + "')") >= 0);
|
|
@@ -2092,18 +2500,26 @@ function switchLeftTab(tab) {
|
|
|
2092
2500
|
}
|
|
2093
2501
|
var inp = document.getElementById('comp-search');
|
|
2094
2502
|
if (tab === 'elements') {
|
|
2095
|
-
inp.placeholder = 'Search elements\u2026';
|
|
2096
2503
|
renderElementsTree(inp.value);
|
|
2097
2504
|
} else if (tab === 'dom-tree') {
|
|
2098
|
-
inp.placeholder = 'Search layers\u2026';
|
|
2099
2505
|
renderDomTree(inp.value);
|
|
2100
2506
|
}
|
|
2101
2507
|
}
|
|
2102
2508
|
|
|
2509
|
+
function expandSectionComponentsBody() {
|
|
2510
|
+
var panel = document.getElementById('section-components-panel');
|
|
2511
|
+
if (!panel) return;
|
|
2512
|
+
var body = panel.querySelector('.lp-body');
|
|
2513
|
+
var toggle = panel.querySelector('.close-section-components-panel');
|
|
2514
|
+
if (body) body.classList.remove('collapsed');
|
|
2515
|
+
if (toggle) toggle.classList.remove('collapsed');
|
|
2516
|
+
}
|
|
2517
|
+
|
|
2103
2518
|
function switchSectionComponentsTab(tab) {
|
|
2104
2519
|
if (tab !== 'components' && tab !== 'sections') return;
|
|
2520
|
+
expandSectionComponentsBody();
|
|
2105
2521
|
currentSectionComponentsTab = tab;
|
|
2106
|
-
var tabs = document.querySelectorAll('
|
|
2522
|
+
var tabs = document.querySelectorAll('#section-components-panel .lp-tabs .lp-tab');
|
|
2107
2523
|
for (var i = 0; i < tabs.length; i++) {
|
|
2108
2524
|
var oc = tabs[i].getAttribute('onclick') || '';
|
|
2109
2525
|
tabs[i].classList.toggle('active', oc.indexOf("switchSectionComponentsTab('" + tab + "')") >= 0);
|
|
@@ -2113,29 +2529,67 @@ function switchSectionComponentsTab(tab) {
|
|
|
2113
2529
|
if (compPane) compPane.classList.toggle('active', tab === 'components');
|
|
2114
2530
|
if (secPane) secPane.classList.toggle('active', tab === 'sections');
|
|
2115
2531
|
var inp = document.getElementById('comp-search');
|
|
2116
|
-
if (inp) inp.placeholder = tab === 'sections' ? 'Search
|
|
2532
|
+
if (inp) inp.placeholder = tab === 'sections' ? 'Search' : 'Search';
|
|
2117
2533
|
renderSidebar(inp ? inp.value : '');
|
|
2118
2534
|
}
|
|
2119
2535
|
|
|
2536
|
+
function toggleSectionComponentsBody() {
|
|
2537
|
+
var panel = document.getElementById('section-components-panel');
|
|
2538
|
+
if (!panel) return;
|
|
2539
|
+
var body = panel.querySelector('.lp-body');
|
|
2540
|
+
var toggle = panel.querySelector('.close-section-components-panel');
|
|
2541
|
+
if (!body) return;
|
|
2542
|
+
var collapsed = body.classList.toggle('collapsed');
|
|
2543
|
+
if (toggle) toggle.classList.toggle('collapsed', collapsed);
|
|
2544
|
+
}
|
|
2545
|
+
|
|
2120
2546
|
function toggleSectionComponentsPanel(forceVisible) {
|
|
2121
2547
|
var panel = document.getElementById('section-components-panel');
|
|
2122
2548
|
if (!panel) return;
|
|
2123
|
-
var
|
|
2549
|
+
var body = panel.querySelector('.lp-body');
|
|
2550
|
+
var toggle = panel.querySelector('.close-section-components-panel');
|
|
2551
|
+
if (!body) return;
|
|
2552
|
+
var isCollapsed = body.classList.contains('collapsed');
|
|
2553
|
+
var shouldExpand =
|
|
2124
2554
|
typeof forceVisible === 'boolean'
|
|
2125
2555
|
? forceVisible
|
|
2126
|
-
:
|
|
2127
|
-
|
|
2128
|
-
if (
|
|
2556
|
+
: isCollapsed;
|
|
2557
|
+
body.classList.toggle('collapsed', !shouldExpand);
|
|
2558
|
+
if (toggle) toggle.classList.toggle('collapsed', !shouldExpand);
|
|
2559
|
+
if (shouldExpand) {
|
|
2129
2560
|
switchSectionComponentsTab(currentSectionComponentsTab || 'components');
|
|
2130
2561
|
}
|
|
2131
2562
|
}
|
|
2132
2563
|
|
|
2564
|
+
function handleAddElementClick(e) {
|
|
2565
|
+
if (e) {
|
|
2566
|
+
e.preventDefault();
|
|
2567
|
+
e.stopPropagation();
|
|
2568
|
+
}
|
|
2569
|
+
toggleSectionComponentsPanel();
|
|
2570
|
+
}
|
|
2571
|
+
|
|
2133
2572
|
// \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
|
|
2134
2573
|
function toggleAcc(name) {
|
|
2135
2574
|
var sec = document.getElementById('acc-' + name);
|
|
2136
2575
|
if (sec) sec.classList.toggle('open');
|
|
2137
2576
|
}
|
|
2138
2577
|
|
|
2578
|
+
function focusDesignAccordionSection(name) {
|
|
2579
|
+
if (!name) return;
|
|
2580
|
+
if (currentMainTab !== 'design') switchMainTab('design');
|
|
2581
|
+
var sec = document.getElementById('acc-' + name);
|
|
2582
|
+
if (!sec || sec.style.display === 'none') return;
|
|
2583
|
+
sec.classList.add('open');
|
|
2584
|
+
requestAnimationFrame(function() {
|
|
2585
|
+
try {
|
|
2586
|
+
sec.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
|
2587
|
+
} catch(_) {
|
|
2588
|
+
sec.scrollIntoView(true);
|
|
2589
|
+
}
|
|
2590
|
+
});
|
|
2591
|
+
}
|
|
2592
|
+
|
|
2139
2593
|
// \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
|
|
2140
2594
|
function switchMainTab(tab) {
|
|
2141
2595
|
currentMainTab = tab;
|
|
@@ -2200,9 +2654,19 @@ var PROP_META = {
|
|
|
2200
2654
|
'pp-id': {label:'ID', cssProp:null},
|
|
2201
2655
|
'pp-href': {label:'Href', cssProp:null},
|
|
2202
2656
|
'pp-target': {label:'Target', cssProp:null},
|
|
2657
|
+
'pp-rel': {label:'Rel', cssProp:null},
|
|
2658
|
+
'pp-download':{label:'Download', cssProp:null},
|
|
2659
|
+
'pp-link-title': {label:'Title', cssProp:null},
|
|
2660
|
+
'pp-hreflang':{label:'Hreflang', cssProp:null},
|
|
2661
|
+
'pp-link-type': {label:'Link type', cssProp:null},
|
|
2662
|
+
'pp-referrerpolicy': {label:'Referrer policy', cssProp:null},
|
|
2203
2663
|
'pp-src': {label:'Src', cssProp:null},
|
|
2664
|
+
'pp-video-src': {label:'Src', cssProp:null},
|
|
2665
|
+
'pp-youtube-id': {label:'YouTube video ID', cssProp:null},
|
|
2666
|
+
'pp-vimeo-id': {label:'Vimeo video ID', cssProp:null},
|
|
2204
2667
|
'pp-alt': {label:'Alt', cssProp:null},
|
|
2205
2668
|
'pp-ph': {label:'Placeholder', cssProp:null},
|
|
2669
|
+
'pp-value': {label:'Value', cssProp:null},
|
|
2206
2670
|
'pp-text': {label:'Inner text', cssProp:null},
|
|
2207
2671
|
'pp-html': {label:'Inner HTML', cssProp:null},
|
|
2208
2672
|
'pp-mob-css': {label:'Mobile CSS', cssProp:null},
|
|
@@ -2225,9 +2689,19 @@ function getOriginalValue(inputId, el) {
|
|
|
2225
2689
|
case 'pp-id': return el.id || '';
|
|
2226
2690
|
case 'pp-href': return el.getAttribute('href') || '';
|
|
2227
2691
|
case 'pp-target': return el.getAttribute('target') || '';
|
|
2692
|
+
case 'pp-rel': return el.getAttribute('rel') || '';
|
|
2693
|
+
case 'pp-download': return el.getAttribute('download') || '';
|
|
2694
|
+
case 'pp-link-title': return el.getAttribute('title') || '';
|
|
2695
|
+
case 'pp-hreflang': return el.getAttribute('hreflang') || '';
|
|
2696
|
+
case 'pp-link-type': return el.getAttribute('type') || '';
|
|
2697
|
+
case 'pp-referrerpolicy': return el.getAttribute('referrerpolicy') || '';
|
|
2228
2698
|
case 'pp-src': return el.getAttribute('src') || '';
|
|
2699
|
+
case 'pp-video-src': return getVideoSrc(el);
|
|
2700
|
+
case 'pp-youtube-id': return getYoutubeVideoId(el);
|
|
2701
|
+
case 'pp-vimeo-id': return getVimeoVideoId(el);
|
|
2229
2702
|
case 'pp-alt': return el.getAttribute('alt') || '';
|
|
2230
2703
|
case 'pp-ph': return el.getAttribute('placeholder') || '';
|
|
2704
|
+
case 'pp-value': return getFormControlValue(el);
|
|
2231
2705
|
case 'pp-css': return el.getAttribute('style') || '';
|
|
2232
2706
|
case 'pp-mob-css': return el.dataset.mobileCss || '';
|
|
2233
2707
|
case 'pp-tab-css': return el.dataset.tabletCss || '';
|
|
@@ -2364,9 +2838,19 @@ function revertChangeOnDom(change) {
|
|
|
2364
2838
|
case 'pp-css': orig ? el.setAttribute('style', orig) : el.removeAttribute('style'); break;
|
|
2365
2839
|
case 'pp-href': orig ? el.setAttribute('href', orig) : el.removeAttribute('href'); break;
|
|
2366
2840
|
case 'pp-target': orig ? el.setAttribute('target', orig) : el.removeAttribute('target'); break;
|
|
2841
|
+
case 'pp-rel': orig ? el.setAttribute('rel', orig) : el.removeAttribute('rel'); break;
|
|
2842
|
+
case 'pp-download': orig ? el.setAttribute('download', orig) : el.removeAttribute('download'); break;
|
|
2843
|
+
case 'pp-link-title': orig ? el.setAttribute('title', orig) : el.removeAttribute('title'); break;
|
|
2844
|
+
case 'pp-hreflang': orig ? el.setAttribute('hreflang', orig) : el.removeAttribute('hreflang'); break;
|
|
2845
|
+
case 'pp-link-type': orig ? el.setAttribute('type', orig) : el.removeAttribute('type'); break;
|
|
2846
|
+
case 'pp-referrerpolicy': orig ? el.setAttribute('referrerpolicy', orig) : el.removeAttribute('referrerpolicy'); break;
|
|
2367
2847
|
case 'pp-src': orig ? el.setAttribute('src', orig) : el.removeAttribute('src'); break;
|
|
2848
|
+
case 'pp-video-src': orig ? setVideoSrc(el, orig) : setVideoSrc(el, ''); break;
|
|
2849
|
+
case 'pp-youtube-id': orig ? setYoutubeVideoId(el, orig) : setYoutubeVideoId(el, ''); break;
|
|
2850
|
+
case 'pp-vimeo-id': orig ? setVimeoVideoId(el, orig) : setVimeoVideoId(el, ''); break;
|
|
2368
2851
|
case 'pp-alt': orig ? el.setAttribute('alt', orig) : el.removeAttribute('alt'); break;
|
|
2369
2852
|
case 'pp-ph': orig ? el.setAttribute('placeholder', orig) : el.removeAttribute('placeholder'); break;
|
|
2853
|
+
case 'pp-value': el.value = orig; break;
|
|
2370
2854
|
case 'pp-mob-css': el.dataset.mobileCss = orig; break;
|
|
2371
2855
|
case 'pp-tab-css': el.dataset.tabletCss = orig; break;
|
|
2372
2856
|
default: console.warn('[V2] revertChangeOnDom: no revert handler for', change.inputId);
|
|
@@ -2390,11 +2874,28 @@ function syncDesignInput(change) {
|
|
|
2390
2874
|
function removeStateChange(idx) {
|
|
2391
2875
|
var change = stateChanges[idx];
|
|
2392
2876
|
if (!change) return;
|
|
2877
|
+
if (
|
|
2878
|
+
change.isStructuralLive &&
|
|
2879
|
+
normalizeChangesetType({ type: change.structuralType }) === 'insert'
|
|
2880
|
+
) {
|
|
2881
|
+
var instId = historyInsertInstanceId(null, change);
|
|
2882
|
+
if (instId) {
|
|
2883
|
+
removeEditorInsertByInstanceId(instId);
|
|
2884
|
+
commitStateChangesForActiveVariation();
|
|
2885
|
+
renderStatesTab();
|
|
2886
|
+
if (currentMainTab === 'history') renderHistoryTab();
|
|
2887
|
+
try {
|
|
2888
|
+
delete varHtmlCache[activeVarId];
|
|
2889
|
+
} catch(_) {}
|
|
2890
|
+
saveCurrentVariationHtml();
|
|
2891
|
+
recomputeEditorDirty();
|
|
2892
|
+
scheduleDomTreeRefresh();
|
|
2893
|
+
return;
|
|
2894
|
+
}
|
|
2895
|
+
}
|
|
2393
2896
|
if (change.isStructuralLive) {
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
change.vveTs,
|
|
2397
|
-
);
|
|
2897
|
+
var varId = change.structuralVarId || activeVarId;
|
|
2898
|
+
removeSessionStructuralRowByTimestamp(varId, change.vveTs);
|
|
2398
2899
|
stateChanges.splice(idx, 1);
|
|
2399
2900
|
commitStateChangesForActiveVariation();
|
|
2400
2901
|
renderStatesTab();
|
|
@@ -2492,10 +2993,28 @@ function captureChangesetSnapshotBeforeApply(entry, el, iframeDoc) {
|
|
|
2492
2993
|
break;
|
|
2493
2994
|
case 'attribute':
|
|
2494
2995
|
if (entry.attribute) {
|
|
2996
|
+
var attrVal = el.getAttribute(entry.attribute);
|
|
2997
|
+
if (
|
|
2998
|
+
String(entry.attribute).toLowerCase() === 'src' &&
|
|
2999
|
+
el.tagName &&
|
|
3000
|
+
el.tagName.toLowerCase() === 'video'
|
|
3001
|
+
) {
|
|
3002
|
+
attrVal = getVideoSrc(el);
|
|
3003
|
+
} else if (
|
|
3004
|
+
String(entry.attribute).toLowerCase() === 'data-youtube-id' &&
|
|
3005
|
+
isYoutubeVideoElement(el)
|
|
3006
|
+
) {
|
|
3007
|
+
attrVal = getYoutubeVideoId(el);
|
|
3008
|
+
} else if (
|
|
3009
|
+
String(entry.attribute).toLowerCase() === 'data-vimeo-id' &&
|
|
3010
|
+
isVimeoVideoElement(el)
|
|
3011
|
+
) {
|
|
3012
|
+
attrVal = getVimeoVideoId(el);
|
|
3013
|
+
}
|
|
2495
3014
|
appliedChangesetSnapshots[k] = {
|
|
2496
3015
|
kind: 'attribute',
|
|
2497
3016
|
name: entry.attribute,
|
|
2498
|
-
v:
|
|
3017
|
+
v: attrVal,
|
|
2499
3018
|
};
|
|
2500
3019
|
}
|
|
2501
3020
|
break;
|
|
@@ -2544,6 +3063,13 @@ function revertChangesetEntryOnDom(entry) {
|
|
|
2544
3063
|
var iframeDoc = document.getElementById('iframeId').contentDocument;
|
|
2545
3064
|
if (!iframeDoc) return false;
|
|
2546
3065
|
var k = entrySnapshotKey(entry);
|
|
3066
|
+
if (normalizeChangesetType(entry) === 'insert') {
|
|
3067
|
+
var instId = instanceIdFromInsertHtml(entry.html);
|
|
3068
|
+
delete appliedChangesetSnapshots[k];
|
|
3069
|
+
if (instId && removeEditorInsertByInstanceId(instId)) return false;
|
|
3070
|
+
softReloadEditorIframe();
|
|
3071
|
+
return true;
|
|
3072
|
+
}
|
|
2547
3073
|
var snap = appliedChangesetSnapshots[k];
|
|
2548
3074
|
var el = querySelectorResolved(iframeDoc, entry.selector);
|
|
2549
3075
|
if (!snap || !el) {
|
|
@@ -2562,7 +3088,23 @@ function revertChangesetEntryOnDom(entry) {
|
|
|
2562
3088
|
if (snap.v) el.setAttribute('style', snap.v);
|
|
2563
3089
|
else el.removeAttribute('style');
|
|
2564
3090
|
} else if (snap.kind === 'attribute' && snap.name) {
|
|
2565
|
-
if (
|
|
3091
|
+
if (
|
|
3092
|
+
String(snap.name).toLowerCase() === 'src' &&
|
|
3093
|
+
el.tagName &&
|
|
3094
|
+
el.tagName.toLowerCase() === 'video'
|
|
3095
|
+
) {
|
|
3096
|
+
setVideoSrc(el, snap.v == null ? '' : snap.v);
|
|
3097
|
+
} else if (
|
|
3098
|
+
String(snap.name).toLowerCase() === 'data-youtube-id' &&
|
|
3099
|
+
isYoutubeVideoElement(el)
|
|
3100
|
+
) {
|
|
3101
|
+
setYoutubeVideoId(el, snap.v == null ? '' : snap.v);
|
|
3102
|
+
} else if (
|
|
3103
|
+
String(snap.name).toLowerCase() === 'data-vimeo-id' &&
|
|
3104
|
+
isVimeoVideoElement(el)
|
|
3105
|
+
) {
|
|
3106
|
+
setVimeoVideoId(el, snap.v == null ? '' : snap.v);
|
|
3107
|
+
} else if (snap.v == null || snap.v === '') el.removeAttribute(snap.name);
|
|
2566
3108
|
else el.setAttribute(snap.name, snap.v);
|
|
2567
3109
|
} else if (snap.kind === 'display') el.style.display = snap.v;
|
|
2568
3110
|
else {
|
|
@@ -2643,6 +3185,42 @@ function formatHistoryRelativeTime(ts) {
|
|
|
2643
3185
|
return day + ' day' + (day === 1 ? '' : 's') + ' ago';
|
|
2644
3186
|
}
|
|
2645
3187
|
|
|
3188
|
+
function findSessionInsertRowForChange(change) {
|
|
3189
|
+
if (!change) return null;
|
|
3190
|
+
var varId = change.structuralVarId || activeVarId;
|
|
3191
|
+
var arr = varId && sessionStructuralChainRowsByVarId[varId];
|
|
3192
|
+
if (!arr || !arr.length) return null;
|
|
3193
|
+
var instId = '';
|
|
3194
|
+
try {
|
|
3195
|
+
if (change.targetEl && change.targetEl.getAttribute) {
|
|
3196
|
+
instId = change.targetEl.getAttribute('data-vve-instance') || '';
|
|
3197
|
+
}
|
|
3198
|
+
} catch(_) {}
|
|
3199
|
+
for (var i = 0; i < arr.length; i++) {
|
|
3200
|
+
var row = arr[i];
|
|
3201
|
+
if (!row || normalizeChangesetType(row) !== 'insert') continue;
|
|
3202
|
+
if (change.vveTs && row.vveTs === change.vveTs) return row;
|
|
3203
|
+
if (instId && instanceIdFromInsertHtml(row.html) === instId) return row;
|
|
3204
|
+
}
|
|
3205
|
+
return null;
|
|
3206
|
+
}
|
|
3207
|
+
|
|
3208
|
+
function historyInsertInstanceId(entry, change) {
|
|
3209
|
+
if (entry && normalizeChangesetType(entry) === 'insert') {
|
|
3210
|
+
return instanceIdFromInsertHtml(entry.html);
|
|
3211
|
+
}
|
|
3212
|
+
if (change && change.isStructuralLive && normalizeChangesetType({ type: change.structuralType }) === 'insert') {
|
|
3213
|
+
var row = findSessionInsertRowForChange(change);
|
|
3214
|
+
if (row) return instanceIdFromInsertHtml(row.html);
|
|
3215
|
+
try {
|
|
3216
|
+
if (change.targetEl && change.targetEl.getAttribute) {
|
|
3217
|
+
return change.targetEl.getAttribute('data-vve-instance') || '';
|
|
3218
|
+
}
|
|
3219
|
+
} catch(_) {}
|
|
3220
|
+
}
|
|
3221
|
+
return '';
|
|
3222
|
+
}
|
|
3223
|
+
|
|
2646
3224
|
function getUnifiedHistoryItems() {
|
|
2647
3225
|
var out = [];
|
|
2648
3226
|
var v = getActiveVariationForHistory();
|
|
@@ -2652,6 +3230,7 @@ function getUnifiedHistoryItems() {
|
|
|
2652
3230
|
out.push({
|
|
2653
3231
|
source: 'saved',
|
|
2654
3232
|
idx: i,
|
|
3233
|
+
insertInstanceId: historyInsertInstanceId(e, null),
|
|
2655
3234
|
selector: (e && e.selector) || '(unknown)',
|
|
2656
3235
|
label: historyEntryTypeLabel(e),
|
|
2657
3236
|
value: historyEntryValuePreview(e),
|
|
@@ -2668,6 +3247,7 @@ function getUnifiedHistoryItems() {
|
|
|
2668
3247
|
out.push({
|
|
2669
3248
|
source: 'live',
|
|
2670
3249
|
idx: j,
|
|
3250
|
+
insertInstanceId: historyInsertInstanceId(null, c),
|
|
2671
3251
|
selector: c.selector || '(unknown)',
|
|
2672
3252
|
label: c.label || 'Live change',
|
|
2673
3253
|
value: c.value != null ? String(c.value).slice(0, 120) : '',
|
|
@@ -2701,11 +3281,15 @@ function renderHistoryTab() {
|
|
|
2701
3281
|
var title = 'Edit - ' + (it.label || 'Change');
|
|
2702
3282
|
var avatarLabel = it.source === 'live' ? 'Y' : 'S';
|
|
2703
3283
|
var timeText = formatHistoryRelativeTime(it.ts) || (it.tsLabel || '');
|
|
3284
|
+
var removeOnclick = it.insertInstanceId
|
|
3285
|
+
? 'removeHistoryItem("' + esc(it.source) + '",' + it.idx + ', event, "' + esc(it.insertInstanceId) + '")'
|
|
3286
|
+
: 'removeHistoryItem("' + esc(it.source) + '",' + it.idx + ', event)';
|
|
2704
3287
|
html +=
|
|
2705
3288
|
'<div class="history-item" role="button" tabindex="0" title="Jump to element in iframe" onclick="focusHistoryItem("' +
|
|
2706
3289
|
esc(it.source) +
|
|
2707
3290
|
'",' +
|
|
2708
3291
|
it.idx +
|
|
3292
|
+
(it.insertInstanceId ? ', "' + esc(it.insertInstanceId) + '"' : '') +
|
|
2709
3293
|
')">' +
|
|
2710
3294
|
'<span class="history-dot"></span>' +
|
|
2711
3295
|
'<div class="history-card">' +
|
|
@@ -2716,18 +3300,16 @@ function renderHistoryTab() {
|
|
|
2716
3300
|
'</div>' +
|
|
2717
3301
|
'<div class="history-time">' + esc(timeText || 'n/a') + '</div>' +
|
|
2718
3302
|
'</div>' +
|
|
2719
|
-
'<button type="button" class="state-remove history-remove" title="Remove this change" onclick="
|
|
2720
|
-
|
|
2721
|
-
'
|
|
2722
|
-
it.idx +
|
|
2723
|
-
', event)">✕</button>' +
|
|
3303
|
+
'<button type="button" class="state-remove history-remove" title="Remove this change" onclick="' +
|
|
3304
|
+
removeOnclick +
|
|
3305
|
+
'">✕</button>' +
|
|
2724
3306
|
'</div>';
|
|
2725
3307
|
}
|
|
2726
3308
|
html += '</div>';
|
|
2727
3309
|
container.innerHTML = html;
|
|
2728
3310
|
}
|
|
2729
3311
|
|
|
2730
|
-
function focusHistoryItem(source, idx) {
|
|
3312
|
+
function focusHistoryItem(source, idx, insertInstanceId) {
|
|
2731
3313
|
if (source === 'live') {
|
|
2732
3314
|
var change = stateChanges[idx];
|
|
2733
3315
|
if (!change || !change.selector) return;
|
|
@@ -2735,6 +3317,20 @@ function focusHistoryItem(source, idx) {
|
|
|
2735
3317
|
var iframe = document.getElementById('iframeId');
|
|
2736
3318
|
var iframeDoc = iframe && iframe.contentDocument;
|
|
2737
3319
|
if (!iframeDoc) return;
|
|
3320
|
+
var instId = insertInstanceId || historyInsertInstanceId(null, change);
|
|
3321
|
+
if (instId) {
|
|
3322
|
+
var safeInst = String(instId).split('"').join('\\"');
|
|
3323
|
+
var insertedEl = iframeDoc.querySelector('[data-vve-instance="' + safeInst + '"]');
|
|
3324
|
+
if (insertedEl) {
|
|
3325
|
+
selectElement(insertedEl);
|
|
3326
|
+
try {
|
|
3327
|
+
insertedEl.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'nearest' });
|
|
3328
|
+
} catch(_) {
|
|
3329
|
+
insertedEl.scrollIntoView();
|
|
3330
|
+
}
|
|
3331
|
+
return;
|
|
3332
|
+
}
|
|
3333
|
+
}
|
|
2738
3334
|
var el = querySelectorResolved(iframeDoc, change.selector);
|
|
2739
3335
|
if (!el) return;
|
|
2740
3336
|
selectElement(el);
|
|
@@ -2746,12 +3342,25 @@ function focusHistoryItem(source, idx) {
|
|
|
2746
3342
|
} catch(_) {}
|
|
2747
3343
|
return;
|
|
2748
3344
|
}
|
|
2749
|
-
focusHistoryChangeset(idx);
|
|
3345
|
+
focusHistoryChangeset(idx, insertInstanceId);
|
|
2750
3346
|
}
|
|
2751
3347
|
|
|
2752
|
-
function removeHistoryItem(source, idx, evt) {
|
|
3348
|
+
function removeHistoryItem(source, idx, evt, insertInstanceId) {
|
|
3349
|
+
if (evt && evt.stopPropagation) evt.stopPropagation();
|
|
3350
|
+
if (insertInstanceId) {
|
|
3351
|
+
removeEditorInsertByInstanceId(insertInstanceId);
|
|
3352
|
+
commitStateChangesForActiveVariation();
|
|
3353
|
+
try {
|
|
3354
|
+
delete varHtmlCache[activeVarId];
|
|
3355
|
+
} catch(_) {}
|
|
3356
|
+
saveCurrentVariationHtml();
|
|
3357
|
+
recomputeEditorDirty();
|
|
3358
|
+
if (currentMainTab === 'states') renderStatesTab();
|
|
3359
|
+
if (currentMainTab === 'history') renderHistoryTab();
|
|
3360
|
+
scheduleDomTreeRefresh();
|
|
3361
|
+
return;
|
|
3362
|
+
}
|
|
2753
3363
|
if (source === 'live') {
|
|
2754
|
-
if (evt && evt.stopPropagation) evt.stopPropagation();
|
|
2755
3364
|
removeStateChange(idx);
|
|
2756
3365
|
if (currentMainTab === 'history') renderHistoryTab();
|
|
2757
3366
|
return;
|
|
@@ -2790,7 +3399,7 @@ function isStyleOnlyChangesetEntry(entry) {
|
|
|
2790
3399
|
return false;
|
|
2791
3400
|
}
|
|
2792
3401
|
|
|
2793
|
-
function focusHistoryChangeset(idx) {
|
|
3402
|
+
function focusHistoryChangeset(idx, insertInstanceId) {
|
|
2794
3403
|
var v = getActiveVariationForHistory();
|
|
2795
3404
|
if (!v) return;
|
|
2796
3405
|
var arr = parseVariationChangesets(v);
|
|
@@ -2801,6 +3410,20 @@ function focusHistoryChangeset(idx) {
|
|
|
2801
3410
|
var iframe = document.getElementById('iframeId');
|
|
2802
3411
|
var iframeDoc = iframe && iframe.contentDocument;
|
|
2803
3412
|
if (!iframeDoc) return;
|
|
3413
|
+
var instId = insertInstanceId || historyInsertInstanceId(entry, null);
|
|
3414
|
+
if (instId) {
|
|
3415
|
+
var safeInst = String(instId).split('"').join('\\"');
|
|
3416
|
+
var insertedEl = iframeDoc.querySelector('[data-vve-instance="' + safeInst + '"]');
|
|
3417
|
+
if (insertedEl) {
|
|
3418
|
+
selectElement(insertedEl);
|
|
3419
|
+
try {
|
|
3420
|
+
insertedEl.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'nearest' });
|
|
3421
|
+
} catch(_) {
|
|
3422
|
+
insertedEl.scrollIntoView();
|
|
3423
|
+
}
|
|
3424
|
+
return;
|
|
3425
|
+
}
|
|
3426
|
+
}
|
|
2804
3427
|
var el = querySelectorResolved(iframeDoc, entry.selector);
|
|
2805
3428
|
if (!el) return;
|
|
2806
3429
|
selectElement(el);
|
|
@@ -2842,6 +3465,10 @@ function removeHistoryChangeset(idx, evt) {
|
|
|
2842
3465
|
var removedIsStructural = removedType === 'insert' || removedType === 'reorder';
|
|
2843
3466
|
if (didReload) {
|
|
2844
3467
|
/* revertChangesetEntryOnDom already kicked off iframe reload */
|
|
3468
|
+
} else if (removedType === 'insert') {
|
|
3469
|
+
try {
|
|
3470
|
+
saveCurrentVariationHtml();
|
|
3471
|
+
} catch(_) {}
|
|
2845
3472
|
} else if (removedIsStructural) {
|
|
2846
3473
|
softReloadEditorIframe();
|
|
2847
3474
|
} else if (hasStructuralRemaining) {
|
|
@@ -3510,6 +4137,14 @@ function loadPage(proxyUrl) {
|
|
|
3510
4137
|
// \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
|
|
3511
4138
|
var VAR_COLORS = ['#0069A8','#CA3500','#00786F','#ec4899','#14b8a6','#f59e0b','#8b5cf6','#ef4444'];
|
|
3512
4139
|
|
|
4140
|
+
function varColorAlpha(hex, alpha) {
|
|
4141
|
+
var h = hex.slice(1);
|
|
4142
|
+
return 'rgba(' +
|
|
4143
|
+
parseInt(h.slice(0, 2), 16) + ',' +
|
|
4144
|
+
parseInt(h.slice(2, 4), 16) + ',' +
|
|
4145
|
+
parseInt(h.slice(4, 6), 16) + ',' + alpha + ')';
|
|
4146
|
+
}
|
|
4147
|
+
|
|
3513
4148
|
function renderVariationTabs() {
|
|
3514
4149
|
var container = document.getElementById('variation-tabs');
|
|
3515
4150
|
container.innerHTML = '';
|
|
@@ -3521,7 +4156,12 @@ function renderVariationTabs() {
|
|
|
3521
4156
|
btn.onclick = function() { switchVariation(v._id); };
|
|
3522
4157
|
var dot = document.createElement('span');
|
|
3523
4158
|
dot.className = 'var-dot';
|
|
3524
|
-
|
|
4159
|
+
var color = VAR_COLORS[i % VAR_COLORS.length];
|
|
4160
|
+
btn.setAttribute('data-color', color);
|
|
4161
|
+
btn.style.setProperty('--var-tab-color', color);
|
|
4162
|
+
dot.setAttribute('data-color', color);
|
|
4163
|
+
dot.style.background = color;
|
|
4164
|
+
dot.style.boxShadow = '0 0 0 3px ' + varColorAlpha(color, 0.5);
|
|
3525
4165
|
btn.appendChild(dot);
|
|
3526
4166
|
btn.appendChild(document.createTextNode(label));
|
|
3527
4167
|
container.appendChild(btn);
|
|
@@ -3722,6 +4362,29 @@ function removeSessionStructuralRowByTimestamp(varId, ts) {
|
|
|
3722
4362
|
}
|
|
3723
4363
|
}
|
|
3724
4364
|
|
|
4365
|
+
function removeStructuralStateChangeByTimestamp(varId, ts) {
|
|
4366
|
+
if (!varId || !ts) return;
|
|
4367
|
+
for (var i = stateChanges.length - 1; i >= 0; i--) {
|
|
4368
|
+
var c = stateChanges[i];
|
|
4369
|
+
if (
|
|
4370
|
+
c &&
|
|
4371
|
+
c.isStructuralLive &&
|
|
4372
|
+
c.vveTs === ts &&
|
|
4373
|
+
(c.structuralVarId || activeVarId) === varId
|
|
4374
|
+
) {
|
|
4375
|
+
stateChanges.splice(i, 1);
|
|
4376
|
+
}
|
|
4377
|
+
}
|
|
4378
|
+
}
|
|
4379
|
+
|
|
4380
|
+
/** Undo a session insert when its root node is deleted \u2014 avoids orphan remove rows that match re-inserts at the same slot. */
|
|
4381
|
+
function cancelSessionInsertForElement(varId, el) {
|
|
4382
|
+
if (!varId || !el) return false;
|
|
4383
|
+
var inst = el.getAttribute && el.getAttribute('data-vve-instance');
|
|
4384
|
+
if (!inst || !String(inst).trim()) return false;
|
|
4385
|
+
return removeEditorInsertByInstanceId(inst, { skipDom: true, varId: varId });
|
|
4386
|
+
}
|
|
4387
|
+
|
|
3725
4388
|
/** One States-tab row -> Conversion.io chain-set shape (matches applyChangesetEntry). */
|
|
3726
4389
|
function stateChangeToChainSet(c) {
|
|
3727
4390
|
if (!c || !c.selector) return null;
|
|
@@ -3747,12 +4410,32 @@ function stateChangeToChainSet(c) {
|
|
|
3747
4410
|
return { selector: c.selector, type: 'attribute', attribute: 'href', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
3748
4411
|
case 'pp-target':
|
|
3749
4412
|
return { selector: c.selector, type: 'attribute', attribute: 'target', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4413
|
+
case 'pp-rel':
|
|
4414
|
+
return { selector: c.selector, type: 'attribute', attribute: 'rel', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4415
|
+
case 'pp-download':
|
|
4416
|
+
return { selector: c.selector, type: 'attribute', attribute: 'download', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4417
|
+
case 'pp-link-title':
|
|
4418
|
+
return { selector: c.selector, type: 'attribute', attribute: 'title', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4419
|
+
case 'pp-hreflang':
|
|
4420
|
+
return { selector: c.selector, type: 'attribute', attribute: 'hreflang', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4421
|
+
case 'pp-link-type':
|
|
4422
|
+
return { selector: c.selector, type: 'attribute', attribute: 'type', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4423
|
+
case 'pp-referrerpolicy':
|
|
4424
|
+
return { selector: c.selector, type: 'attribute', attribute: 'referrerpolicy', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
3750
4425
|
case 'pp-src':
|
|
3751
4426
|
return { selector: c.selector, type: 'attribute', attribute: 'src', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4427
|
+
case 'pp-video-src':
|
|
4428
|
+
return { selector: c.selector, type: 'attribute', attribute: 'src', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4429
|
+
case 'pp-youtube-id':
|
|
4430
|
+
return { selector: c.selector, type: 'attribute', attribute: 'data-youtube-id', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4431
|
+
case 'pp-vimeo-id':
|
|
4432
|
+
return { selector: c.selector, type: 'attribute', attribute: 'data-vimeo-id', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
3752
4433
|
case 'pp-alt':
|
|
3753
4434
|
return { selector: c.selector, type: 'attribute', attribute: 'alt', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
3754
4435
|
case 'pp-ph':
|
|
3755
4436
|
return { selector: c.selector, type: 'attribute', attribute: 'placeholder', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4437
|
+
case 'pp-value':
|
|
4438
|
+
return { selector: c.selector, type: 'attribute', attribute: 'value', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
3756
4439
|
case 'pp-css':
|
|
3757
4440
|
return { selector: c.selector, type: 'attribute', attribute: 'style', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
3758
4441
|
case 'pp-mob-css':
|
|
@@ -4012,7 +4695,25 @@ function applyChangesetEntry(entry, iframeDoc) {
|
|
|
4012
4695
|
case 'attribute':
|
|
4013
4696
|
if (entry.attribute && entry.value != null) {
|
|
4014
4697
|
if (String(entry.attribute).toLowerCase() === 'style') break;
|
|
4015
|
-
|
|
4698
|
+
if (
|
|
4699
|
+
String(entry.attribute).toLowerCase() === 'src' &&
|
|
4700
|
+
el.tagName &&
|
|
4701
|
+
el.tagName.toLowerCase() === 'video'
|
|
4702
|
+
) {
|
|
4703
|
+
setVideoSrc(el, entry.value);
|
|
4704
|
+
} else if (
|
|
4705
|
+
String(entry.attribute).toLowerCase() === 'data-youtube-id' &&
|
|
4706
|
+
isYoutubeVideoElement(el)
|
|
4707
|
+
) {
|
|
4708
|
+
setYoutubeVideoId(el, entry.value);
|
|
4709
|
+
} else if (
|
|
4710
|
+
String(entry.attribute).toLowerCase() === 'data-vimeo-id' &&
|
|
4711
|
+
isVimeoVideoElement(el)
|
|
4712
|
+
) {
|
|
4713
|
+
setVimeoVideoId(el, entry.value);
|
|
4714
|
+
} else {
|
|
4715
|
+
el.setAttribute(entry.attribute, entry.value);
|
|
4716
|
+
}
|
|
4016
4717
|
}
|
|
4017
4718
|
break;
|
|
4018
4719
|
case 'insert': {
|
|
@@ -4021,9 +4722,12 @@ function applyChangesetEntry(entry, iframeDoc) {
|
|
|
4021
4722
|
if (structuralDedupeKey) appliedStructuralChangesetKeys[structuralDedupeKey] = true;
|
|
4022
4723
|
break;
|
|
4023
4724
|
}
|
|
4024
|
-
case 'remove':
|
|
4725
|
+
case 'remove': {
|
|
4726
|
+
var inst = el.getAttribute && el.getAttribute('data-vve-instance');
|
|
4727
|
+
if (inst && String(entry.selector || '').indexOf('data-vve-instance') < 0) break;
|
|
4025
4728
|
el.style.display = 'none';
|
|
4026
4729
|
break;
|
|
4730
|
+
}
|
|
4027
4731
|
case 'reorder': {
|
|
4028
4732
|
var target = entry.targetSelector ? querySelectorResolved(iframeDoc, entry.targetSelector) : null;
|
|
4029
4733
|
if (!target || !el.parentNode || !target.parentNode) break;
|
|
@@ -4243,7 +4947,11 @@ function deselectElement(options) {
|
|
|
4243
4947
|
document.getElementById('rp-accordion').style.display = 'none';
|
|
4244
4948
|
document.getElementById('bc-path').textContent = 'No element selected';
|
|
4245
4949
|
document.getElementById('bc-path').style.color = 'var(--text-3)';
|
|
4246
|
-
|
|
4950
|
+
var preserveMainTab =
|
|
4951
|
+
!!(options && options.preserveMainTab) ||
|
|
4952
|
+
currentMainTab === 'history' ||
|
|
4953
|
+
currentMainTab === 'states';
|
|
4954
|
+
if (!preserveMainTab) switchMainTab('design');
|
|
4247
4955
|
if (!skipToolbarUpdate) updateSelectionToolbar();
|
|
4248
4956
|
syncDomTreeSelection();
|
|
4249
4957
|
} finally {
|
|
@@ -4330,6 +5038,30 @@ function setDragHandleActive(on) {
|
|
|
4330
5038
|
}
|
|
4331
5039
|
}
|
|
4332
5040
|
|
|
5041
|
+
function getIframeElementVisualRect(el) {
|
|
5042
|
+
var iframe = document.getElementById('iframeId');
|
|
5043
|
+
if (!el || !iframe) return null;
|
|
5044
|
+
// Element rects from the iframe document are in iframe viewport space, not the shell viewport.
|
|
5045
|
+
var elR = el.getBoundingClientRect();
|
|
5046
|
+
var iframeR = iframe.getBoundingClientRect();
|
|
5047
|
+
var cw = iframe.clientWidth || iframe.offsetWidth || 1;
|
|
5048
|
+
var ch = iframe.clientHeight || iframe.offsetHeight || 1;
|
|
5049
|
+
var scaleX = iframeR.width / cw;
|
|
5050
|
+
var scaleY = iframeR.height / ch;
|
|
5051
|
+
var top = iframeR.top + elR.top * scaleY;
|
|
5052
|
+
var left = iframeR.left + elR.left * scaleX;
|
|
5053
|
+
var width = elR.width * scaleX;
|
|
5054
|
+
var height = elR.height * scaleY;
|
|
5055
|
+
return {
|
|
5056
|
+
left: left,
|
|
5057
|
+
top: top,
|
|
5058
|
+
width: width,
|
|
5059
|
+
height: height,
|
|
5060
|
+
right: left + width,
|
|
5061
|
+
bottom: top + height,
|
|
5062
|
+
};
|
|
5063
|
+
}
|
|
5064
|
+
|
|
4333
5065
|
function positionSelectionToolbar() {
|
|
4334
5066
|
var bar = document.getElementById('selection-floater');
|
|
4335
5067
|
var iframe = document.getElementById('iframeId');
|
|
@@ -4341,16 +5073,20 @@ function positionSelectionToolbar() {
|
|
|
4341
5073
|
renderRightPanel(liveSelected);
|
|
4342
5074
|
syncDomTreeSelection();
|
|
4343
5075
|
}
|
|
4344
|
-
var elR = selectedEl
|
|
4345
|
-
|
|
5076
|
+
var elR = getIframeElementVisualRect(selectedEl);
|
|
5077
|
+
if (!elR) return;
|
|
4346
5078
|
var panelR = panel.getBoundingClientRect();
|
|
4347
|
-
var
|
|
4348
|
-
var
|
|
4349
|
-
|
|
4350
|
-
var
|
|
4351
|
-
|
|
5079
|
+
var panelScrollLeft = panel.scrollLeft || 0;
|
|
5080
|
+
var panelScrollTop = panel.scrollTop || 0;
|
|
5081
|
+
var left = elR.left - panelR.left + panelScrollLeft + elR.width / 2 - bar.offsetWidth / 2;
|
|
5082
|
+
var top = elR.top - panelR.top + panelScrollTop - bar.offsetHeight - 8;
|
|
5083
|
+
if (top < panelScrollTop + 6) top = elR.bottom - panelR.top + panelScrollTop + 8;
|
|
5084
|
+
var minL = panelScrollLeft + 6;
|
|
5085
|
+
var maxL = panelScrollLeft + Math.max(6, panel.clientWidth - bar.offsetWidth - 8);
|
|
5086
|
+
left = Math.max(minL, Math.min(left, maxL));
|
|
4352
5087
|
bar.style.left = Math.round(left) + 'px';
|
|
4353
5088
|
bar.style.top = Math.round(top) + 'px';
|
|
5089
|
+
syncMoveFloaterButtons(selectedEl);
|
|
4354
5090
|
}
|
|
4355
5091
|
|
|
4356
5092
|
function updateSelectionToolbar() {
|
|
@@ -4368,6 +5104,7 @@ function updateSelectionToolbar() {
|
|
|
4368
5104
|
if (selectedEl !== liveSelected) selectedEl = liveSelected;
|
|
4369
5105
|
selectedElFingerprint = buildSelector(liveSelected);
|
|
4370
5106
|
bar.style.display = 'flex';
|
|
5107
|
+
syncMoveFloaterButtons(liveSelected);
|
|
4371
5108
|
requestAnimationFrame(function() { positionSelectionToolbar(); });
|
|
4372
5109
|
}
|
|
4373
5110
|
|
|
@@ -4384,6 +5121,11 @@ function bindSelectionToolbarScroll() {
|
|
|
4384
5121
|
}
|
|
4385
5122
|
selectionScrollWin = w;
|
|
4386
5123
|
w.addEventListener('scroll', onFloaterScroll, true);
|
|
5124
|
+
var panel = document.getElementById('iframe-panel');
|
|
5125
|
+
if (panel && !selectionPanelScrollBound) {
|
|
5126
|
+
selectionPanelScrollBound = true;
|
|
5127
|
+
panel.addEventListener('scroll', onFloaterScroll, { passive: true });
|
|
5128
|
+
}
|
|
4387
5129
|
if (!selectionResizeBound) {
|
|
4388
5130
|
selectionResizeBound = true;
|
|
4389
5131
|
window.addEventListener('resize', onFloaterScroll);
|
|
@@ -4405,7 +5147,6 @@ function scrollIframeElementIntoView(el) {
|
|
|
4405
5147
|
function selectElementFromTree(el) {
|
|
4406
5148
|
selectElement(el);
|
|
4407
5149
|
scrollIframeElementIntoView(el);
|
|
4408
|
-
if (currentMainTab !== 'design') switchMainTab('design');
|
|
4409
5150
|
}
|
|
4410
5151
|
|
|
4411
5152
|
function duplicateSelectedEl() {
|
|
@@ -4478,12 +5219,26 @@ function toggleHideSelectedEl() {
|
|
|
4478
5219
|
|
|
4479
5220
|
function deleteSelectedEl() {
|
|
4480
5221
|
if (!selectedEl || !selectedEl.parentNode) return;
|
|
5222
|
+
var inst = selectedEl.getAttribute && selectedEl.getAttribute('data-vve-instance');
|
|
5223
|
+
if (inst && activeVarId && removeEditorInsertByInstanceId(inst)) {
|
|
5224
|
+
saveCurrentVariationHtml();
|
|
5225
|
+
recomputeEditorDirty();
|
|
5226
|
+
deselectElement();
|
|
5227
|
+
scheduleDomTreeRefresh();
|
|
5228
|
+
if (currentMainTab === 'history') renderHistoryTab();
|
|
5229
|
+
return;
|
|
5230
|
+
}
|
|
4481
5231
|
var delSel = buildSelector(selectedEl);
|
|
5232
|
+
var cancelledInsert =
|
|
5233
|
+
activeVarId && cancelSessionInsertForElement(activeVarId, selectedEl);
|
|
4482
5234
|
selectedEl.remove();
|
|
4483
|
-
if (activeVarId) {
|
|
5235
|
+
if (activeVarId && !cancelledInsert) {
|
|
4484
5236
|
var delRow = { selector: delSel, type: 'remove' };
|
|
4485
5237
|
appendSessionStructuralChainRow(activeVarId, delRow);
|
|
4486
5238
|
logStructuralStateChange(delRow, 'Deleted via toolbar', 'Element removed', null);
|
|
5239
|
+
} else if (cancelledInsert) {
|
|
5240
|
+
commitStateChangesForActiveVariation();
|
|
5241
|
+
if (currentMainTab === 'history') renderHistoryTab();
|
|
4487
5242
|
}
|
|
4488
5243
|
saveCurrentVariationHtml();
|
|
4489
5244
|
recomputeEditorDirty();
|
|
@@ -4510,14 +5265,13 @@ function syncDomTreeSelection() {
|
|
|
4510
5265
|
}
|
|
4511
5266
|
|
|
4512
5267
|
function scheduleDomTreeRefresh() {
|
|
4513
|
-
if (currentLeftTab !== 'elements' && currentLeftTab !== 'dom-tree') return;
|
|
4514
5268
|
if (domTreeRefreshTimer) clearTimeout(domTreeRefreshTimer);
|
|
4515
5269
|
domTreeRefreshTimer = setTimeout(function() {
|
|
4516
5270
|
domTreeRefreshTimer = null;
|
|
4517
5271
|
var inp = document.getElementById('comp-search');
|
|
4518
5272
|
var q = inp ? inp.value : '';
|
|
4519
|
-
|
|
4520
|
-
|
|
5273
|
+
renderElementsTree(q);
|
|
5274
|
+
if (currentLeftTab === 'dom-tree') renderDomTree(q);
|
|
4521
5275
|
}, 150);
|
|
4522
5276
|
}
|
|
4523
5277
|
|
|
@@ -4540,6 +5294,162 @@ function domTreePathSegment(el) {
|
|
|
4540
5294
|
return tag + '[' + idx + ']';
|
|
4541
5295
|
}
|
|
4542
5296
|
|
|
5297
|
+
function instanceIdFromInsertHtml(html) {
|
|
5298
|
+
var m = String(html || '').match(/data-vve-instance=["']([^"']+)["']/);
|
|
5299
|
+
return m ? m[1] : '';
|
|
5300
|
+
}
|
|
5301
|
+
|
|
5302
|
+
function resolveInsertedElementFromEntry(doc, entry) {
|
|
5303
|
+
if (!doc || !entry) return null;
|
|
5304
|
+
var instId = instanceIdFromInsertHtml(entry.html);
|
|
5305
|
+
if (!instId) return null;
|
|
5306
|
+
try {
|
|
5307
|
+
var safe = String(instId).split('"').join('\\"');
|
|
5308
|
+
return doc.querySelector('[data-vve-instance="' + safe + '"]');
|
|
5309
|
+
} catch(_) {
|
|
5310
|
+
return null;
|
|
5311
|
+
}
|
|
5312
|
+
}
|
|
5313
|
+
|
|
5314
|
+
function removeInsertFromDomByEntry(entry, iframeDoc) {
|
|
5315
|
+
if (!entry || !iframeDoc) return false;
|
|
5316
|
+
var insertedEl = resolveInsertedElementFromEntry(iframeDoc, entry);
|
|
5317
|
+
if (!insertedEl || !insertedEl.parentNode) return false;
|
|
5318
|
+
if (
|
|
5319
|
+
selectedEl &&
|
|
5320
|
+
(selectedEl === insertedEl || (insertedEl.contains && insertedEl.contains(selectedEl)))
|
|
5321
|
+
) {
|
|
5322
|
+
deselectElement();
|
|
5323
|
+
}
|
|
5324
|
+
insertedEl.remove();
|
|
5325
|
+
return true;
|
|
5326
|
+
}
|
|
5327
|
+
|
|
5328
|
+
/** Remove an editor insert everywhere (DOM + session + saved changesets + live history), keyed by data-vve-instance. */
|
|
5329
|
+
function removeEditorInsertByInstanceId(instId, opts) {
|
|
5330
|
+
if (!instId || !String(instId).trim()) return false;
|
|
5331
|
+
opts = opts || {};
|
|
5332
|
+
var varId = opts.varId || activeVarId;
|
|
5333
|
+
if (!varId) return false;
|
|
5334
|
+
var needle = 'data-vve-instance="' + String(instId).split('"').join('\\"') + '"';
|
|
5335
|
+
var didWork = false;
|
|
5336
|
+
|
|
5337
|
+
if (!opts.skipDom) {
|
|
5338
|
+
var iframeDoc = document.getElementById('iframeId').contentDocument;
|
|
5339
|
+
if (iframeDoc) {
|
|
5340
|
+
try {
|
|
5341
|
+
var safe = String(instId).split('"').join('\\"');
|
|
5342
|
+
var el = iframeDoc.querySelector('[data-vve-instance="' + safe + '"]');
|
|
5343
|
+
if (el && el.parentNode) {
|
|
5344
|
+
if (
|
|
5345
|
+
selectedEl &&
|
|
5346
|
+
(selectedEl === el || (el.contains && el.contains(selectedEl)))
|
|
5347
|
+
) {
|
|
5348
|
+
deselectElement();
|
|
5349
|
+
}
|
|
5350
|
+
el.remove();
|
|
5351
|
+
didWork = true;
|
|
5352
|
+
}
|
|
5353
|
+
} catch(_) {}
|
|
5354
|
+
}
|
|
5355
|
+
}
|
|
5356
|
+
|
|
5357
|
+
var sessionArr = sessionStructuralChainRowsByVarId[varId];
|
|
5358
|
+
if (sessionArr && sessionArr.length) {
|
|
5359
|
+
for (var i = sessionArr.length - 1; i >= 0; i--) {
|
|
5360
|
+
var row = sessionArr[i];
|
|
5361
|
+
if (!row || normalizeChangesetType(row) !== 'insert' || !row.html) continue;
|
|
5362
|
+
if (String(row.html).indexOf(needle) < 0) continue;
|
|
5363
|
+
var ts = row.vveTs;
|
|
5364
|
+
try {
|
|
5365
|
+
var k = structuralChangesetDedupKey(row);
|
|
5366
|
+
if (k) delete appliedStructuralChangesetKeys[k];
|
|
5367
|
+
} catch(_) {}
|
|
5368
|
+
sessionArr.splice(i, 1);
|
|
5369
|
+
removeStructuralStateChangeByTimestamp(varId, ts);
|
|
5370
|
+
didWork = true;
|
|
5371
|
+
}
|
|
5372
|
+
}
|
|
5373
|
+
|
|
5374
|
+
var v = variations.find(function(x) { return x._id === varId; });
|
|
5375
|
+
if (v) {
|
|
5376
|
+
var saved = parseVariationChangesets(v);
|
|
5377
|
+
var savedChanged = false;
|
|
5378
|
+
for (var si = saved.length - 1; si >= 0; si--) {
|
|
5379
|
+
var entry = saved[si];
|
|
5380
|
+
if (!entry || normalizeChangesetType(entry) !== 'insert' || !entry.html) continue;
|
|
5381
|
+
if (String(entry.html).indexOf(needle) < 0) continue;
|
|
5382
|
+
try {
|
|
5383
|
+
delete appliedChangesetSnapshots[entrySnapshotKey(entry)];
|
|
5384
|
+
} catch(_) {}
|
|
5385
|
+
saved.splice(si, 1);
|
|
5386
|
+
savedChanged = true;
|
|
5387
|
+
didWork = true;
|
|
5388
|
+
}
|
|
5389
|
+
if (savedChanged && varId === activeVarId) persistActiveVariationChangesets(saved);
|
|
5390
|
+
}
|
|
5391
|
+
|
|
5392
|
+
for (var j = stateChanges.length - 1; j >= 0; j--) {
|
|
5393
|
+
var c = stateChanges[j];
|
|
5394
|
+
if (!c || !c.isStructuralLive) continue;
|
|
5395
|
+
if (normalizeChangesetType({ type: c.structuralType }) !== 'insert') continue;
|
|
5396
|
+
var match = false;
|
|
5397
|
+
try {
|
|
5398
|
+
if (c.targetEl && c.targetEl.getAttribute && c.targetEl.getAttribute('data-vve-instance') === instId) {
|
|
5399
|
+
match = true;
|
|
5400
|
+
}
|
|
5401
|
+
} catch(_) {}
|
|
5402
|
+
if (match) {
|
|
5403
|
+
stateChanges.splice(j, 1);
|
|
5404
|
+
didWork = true;
|
|
5405
|
+
}
|
|
5406
|
+
}
|
|
5407
|
+
|
|
5408
|
+
return didWork;
|
|
5409
|
+
}
|
|
5410
|
+
|
|
5411
|
+
/** Live DOM nodes inserted via the visual editor, ordered by changeset/session insert order. */
|
|
5412
|
+
function collectEditorInsertedElements(doc) {
|
|
5413
|
+
if (!doc || !doc.body) return [];
|
|
5414
|
+
var byInst = {};
|
|
5415
|
+
var els;
|
|
5416
|
+
try {
|
|
5417
|
+
els = doc.querySelectorAll('[data-vve-instance]');
|
|
5418
|
+
} catch(_) {
|
|
5419
|
+
els = [];
|
|
5420
|
+
}
|
|
5421
|
+
for (var i = 0; i < els.length; i++) {
|
|
5422
|
+
var el = els[i];
|
|
5423
|
+
if (!el || el.nodeType !== 1) continue;
|
|
5424
|
+
var inst = el.getAttribute('data-vve-instance');
|
|
5425
|
+
if (inst && String(inst).trim()) byInst[String(inst)] = el;
|
|
5426
|
+
}
|
|
5427
|
+
|
|
5428
|
+
var ordered = [];
|
|
5429
|
+
var seen = {};
|
|
5430
|
+
function addEl(el) {
|
|
5431
|
+
if (!el || !el.isConnected) return;
|
|
5432
|
+
var k = el.getAttribute && el.getAttribute('data-vve-instance');
|
|
5433
|
+
if (!k || seen[k]) return;
|
|
5434
|
+
seen[k] = true;
|
|
5435
|
+
ordered.push(el);
|
|
5436
|
+
}
|
|
5437
|
+
|
|
5438
|
+
if (activeVarId) {
|
|
5439
|
+
var variation = variations.find(function(v) { return v._id === activeVarId; });
|
|
5440
|
+
if (variation) {
|
|
5441
|
+
var cs = buildPersistedChainSetsForVariation(variation);
|
|
5442
|
+
for (var j = 0; j < cs.length; j++) {
|
|
5443
|
+
var row = cs[j];
|
|
5444
|
+
if (normalizeChangesetType(row) !== 'insert') continue;
|
|
5445
|
+
var instId = instanceIdFromInsertHtml(row.html);
|
|
5446
|
+
if (instId && byInst[instId]) addEl(byInst[instId]);
|
|
5447
|
+
}
|
|
5448
|
+
}
|
|
5449
|
+
}
|
|
5450
|
+
return ordered;
|
|
5451
|
+
}
|
|
5452
|
+
|
|
4543
5453
|
function renderElementsTree(filterRaw) {
|
|
4544
5454
|
var filterText = (filterRaw || '').toLowerCase().trim();
|
|
4545
5455
|
var root = document.getElementById('elements-root');
|
|
@@ -4547,14 +5457,10 @@ function renderElementsTree(filterRaw) {
|
|
|
4547
5457
|
var iframe = document.getElementById('iframeId');
|
|
4548
5458
|
var doc = iframe && iframe.contentDocument;
|
|
4549
5459
|
if (!isIframeDomReady(iframe, doc)) {
|
|
4550
|
-
root.innerHTML = '<div class="dt-muted">Load a page to see
|
|
5460
|
+
root.innerHTML = '<div class="dt-muted">Load a page to see added elements.</div>';
|
|
4551
5461
|
return;
|
|
4552
5462
|
}
|
|
4553
5463
|
|
|
4554
|
-
function skippable(el) {
|
|
4555
|
-
return isDomTreeSkippableTagName(el.tagName);
|
|
4556
|
-
}
|
|
4557
|
-
|
|
4558
5464
|
function nodeIcon(tag) {
|
|
4559
5465
|
tag = (tag || '').toLowerCase();
|
|
4560
5466
|
if (/^h[1-6]$/.test(tag)) return 'bi bi-type-h1';
|
|
@@ -4574,50 +5480,10 @@ function renderElementsTree(filterRaw) {
|
|
|
4574
5480
|
return tag.toUpperCase();
|
|
4575
5481
|
}
|
|
4576
5482
|
|
|
4577
|
-
|
|
4578
|
-
if (!el || el.nodeType !== 1) return false;
|
|
4579
|
-
if (skippable(el)) return false;
|
|
4580
|
-
var tag = (el.tagName || '').toLowerCase();
|
|
4581
|
-
if (tag !== 'svg') {
|
|
4582
|
-
var p = el.parentElement;
|
|
4583
|
-
while (p) {
|
|
4584
|
-
if ((p.tagName || '').toLowerCase() === 'svg') return false;
|
|
4585
|
-
p = p.parentElement;
|
|
4586
|
-
}
|
|
4587
|
-
}
|
|
4588
|
-
return true;
|
|
4589
|
-
}
|
|
4590
|
-
|
|
4591
|
-
var nodes = [];
|
|
4592
|
-
var i, cursor;
|
|
4593
|
-
try {
|
|
4594
|
-
cursor = doc.createTreeWalker(doc.body, NodeFilter.SHOW_ELEMENT, null);
|
|
4595
|
-
} catch(_) {
|
|
4596
|
-
cursor = null;
|
|
4597
|
-
}
|
|
4598
|
-
if (cursor) {
|
|
4599
|
-
while (cursor.nextNode()) {
|
|
4600
|
-
var node = cursor.currentNode;
|
|
4601
|
-
if (isListableNode(node)) nodes.push(node);
|
|
4602
|
-
if (nodes.length > 4000) break;
|
|
4603
|
-
}
|
|
4604
|
-
} else {
|
|
4605
|
-
function collectFlat(el) {
|
|
4606
|
-
if (!el || !el.children) return;
|
|
4607
|
-
for (var j = 0; j < el.children.length; j++) {
|
|
4608
|
-
var c = el.children[j];
|
|
4609
|
-
if (!isListableNode(c)) continue;
|
|
4610
|
-
nodes.push(c);
|
|
4611
|
-
if (nodes.length > 4000) return;
|
|
4612
|
-
collectFlat(c);
|
|
4613
|
-
if (nodes.length > 4000) return;
|
|
4614
|
-
}
|
|
4615
|
-
}
|
|
4616
|
-
collectFlat(doc.body);
|
|
4617
|
-
}
|
|
5483
|
+
var nodes = collectEditorInsertedElements(doc);
|
|
4618
5484
|
|
|
4619
5485
|
root.innerHTML = '';
|
|
4620
|
-
for (i = 0; i < nodes.length; i++) {
|
|
5486
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
4621
5487
|
var el = nodes[i];
|
|
4622
5488
|
var lblText = labelFor(el);
|
|
4623
5489
|
if (filterText && lblText.toLowerCase().indexOf(filterText) < 0) continue;
|
|
@@ -4655,14 +5521,39 @@ function renderElementsTree(filterRaw) {
|
|
|
4655
5521
|
|
|
4656
5522
|
if (!root.querySelector('.dt-row')) {
|
|
4657
5523
|
root.innerHTML = filterText
|
|
4658
|
-
? '<div class="dt-muted">No elements match your search.</div>'
|
|
4659
|
-
: '<div class="dt-muted">No elements
|
|
5524
|
+
? '<div class="dt-muted">No added elements match your search.</div>'
|
|
5525
|
+
: '<div class="dt-muted">No elements added yet. Use Components or Sections to insert.</div>';
|
|
4660
5526
|
}
|
|
4661
5527
|
root.onmouseleave = function() {
|
|
4662
5528
|
clearTreeHoverHighlight();
|
|
4663
5529
|
};
|
|
4664
5530
|
}
|
|
4665
5531
|
|
|
5532
|
+
function domTreeLabelSuffix(el) {
|
|
5533
|
+
if (el.id != null && el.id !== '') return '#' + String(el.id).slice(0, 40);
|
|
5534
|
+
var cn = el.className && typeof el.className === 'string' ? el.className.trim() : '';
|
|
5535
|
+
if (cn) {
|
|
5536
|
+
var parts = cn.split(/s+/).filter(function(x) { return x.indexOf('vve-') !== 0; }).slice(0, 2).join('.');
|
|
5537
|
+
if (parts) return '.' + parts.slice(0, 56);
|
|
5538
|
+
}
|
|
5539
|
+
return '';
|
|
5540
|
+
}
|
|
5541
|
+
|
|
5542
|
+
function domTreeLabelFor(el) {
|
|
5543
|
+
return (el.tagName || '').toLowerCase() + domTreeLabelSuffix(el);
|
|
5544
|
+
}
|
|
5545
|
+
|
|
5546
|
+
function setDomTreeLabelContent(lbl, el) {
|
|
5547
|
+
var tag = (el.tagName || '').toLowerCase();
|
|
5548
|
+
lbl.textContent = '';
|
|
5549
|
+
var tagSpan = document.createElement('span');
|
|
5550
|
+
tagSpan.className = 'dt-tag';
|
|
5551
|
+
tagSpan.textContent = tag;
|
|
5552
|
+
lbl.appendChild(tagSpan);
|
|
5553
|
+
var suffix = domTreeLabelSuffix(el);
|
|
5554
|
+
if (suffix) lbl.appendChild(document.createTextNode(suffix));
|
|
5555
|
+
}
|
|
5556
|
+
|
|
4666
5557
|
function renderDomTree(filterRaw) {
|
|
4667
5558
|
var filterText = (filterRaw || '').toLowerCase().trim();
|
|
4668
5559
|
var root = document.getElementById('dom-tree-root');
|
|
@@ -4680,14 +5571,7 @@ function renderDomTree(filterRaw) {
|
|
|
4680
5571
|
}
|
|
4681
5572
|
|
|
4682
5573
|
function labelFor(el) {
|
|
4683
|
-
|
|
4684
|
-
if (el.id != null && el.id !== '') return tag + '#' + String(el.id).slice(0, 40);
|
|
4685
|
-
var cn = el.className && typeof el.className === 'string' ? el.className.trim() : '';
|
|
4686
|
-
if (cn) {
|
|
4687
|
-
var parts = cn.split(/s+/).filter(function(x) { return x.indexOf('vve-') !== 0; }).slice(0, 2).join('.');
|
|
4688
|
-
if (parts) return tag + '.' + parts.slice(0, 56);
|
|
4689
|
-
}
|
|
4690
|
-
return tag;
|
|
5574
|
+
return domTreeLabelFor(el);
|
|
4691
5575
|
}
|
|
4692
5576
|
|
|
4693
5577
|
function skippable(el) {
|
|
@@ -4764,7 +5648,7 @@ function renderDomTree(filterRaw) {
|
|
|
4764
5648
|
|
|
4765
5649
|
var lbl = document.createElement('div');
|
|
4766
5650
|
lbl.className = 'dt-lbl';
|
|
4767
|
-
lbl
|
|
5651
|
+
setDomTreeLabelContent(lbl, el);
|
|
4768
5652
|
lbl.title = buildSelector(el);
|
|
4769
5653
|
|
|
4770
5654
|
row.appendChild(chev);
|
|
@@ -4815,6 +5699,189 @@ function pr2(l1, i1, l2, i2) {
|
|
|
4815
5699
|
'<div class="pr2-item"><div class="pr2-lbl">'+l2+'</div>'+i2+'</div></div>';
|
|
4816
5700
|
}
|
|
4817
5701
|
function subLbl(text) { return '<div class="sub-lbl">'+text+'</div>'; }
|
|
5702
|
+
|
|
5703
|
+
function isLinkElement(el) {
|
|
5704
|
+
if (!el || el.nodeType !== 1) return false;
|
|
5705
|
+
var tag = (el.tagName || '').toLowerCase();
|
|
5706
|
+
if (tag === 'a') return true;
|
|
5707
|
+
try {
|
|
5708
|
+
return el.getAttribute && el.getAttribute('role') === 'link';
|
|
5709
|
+
} catch(_) {}
|
|
5710
|
+
return false;
|
|
5711
|
+
}
|
|
5712
|
+
|
|
5713
|
+
function isFormControlElement(el) {
|
|
5714
|
+
if (!el || el.nodeType !== 1) return false;
|
|
5715
|
+
var tag = (el.tagName || '').toLowerCase();
|
|
5716
|
+
return tag === 'input' || tag === 'textarea' || tag === 'select';
|
|
5717
|
+
}
|
|
5718
|
+
|
|
5719
|
+
function getFormControlValue(el) {
|
|
5720
|
+
if (!isFormControlElement(el)) return '';
|
|
5721
|
+
try {
|
|
5722
|
+
return el.value != null ? String(el.value) : '';
|
|
5723
|
+
} catch(_) {
|
|
5724
|
+
return '';
|
|
5725
|
+
}
|
|
5726
|
+
}
|
|
5727
|
+
|
|
5728
|
+
function getVideoSrc(el) {
|
|
5729
|
+
if (!el || el.nodeType !== 1) return '';
|
|
5730
|
+
try {
|
|
5731
|
+
var source = el.querySelector && el.querySelector('source');
|
|
5732
|
+
if (source && source.getAttribute('src')) return source.getAttribute('src') || '';
|
|
5733
|
+
return el.getAttribute('src') || '';
|
|
5734
|
+
} catch(_) {
|
|
5735
|
+
return '';
|
|
5736
|
+
}
|
|
5737
|
+
}
|
|
5738
|
+
|
|
5739
|
+
function setVideoSrc(el, value) {
|
|
5740
|
+
if (!el || el.nodeType !== 1) return;
|
|
5741
|
+
var v = value == null ? '' : String(value);
|
|
5742
|
+
try {
|
|
5743
|
+
var source = el.querySelector && el.querySelector('source');
|
|
5744
|
+
if (source) {
|
|
5745
|
+
if (v) source.setAttribute('src', v);
|
|
5746
|
+
else source.removeAttribute('src');
|
|
5747
|
+
} else if (v) {
|
|
5748
|
+
el.setAttribute('src', v);
|
|
5749
|
+
} else {
|
|
5750
|
+
el.removeAttribute('src');
|
|
5751
|
+
}
|
|
5752
|
+
try {
|
|
5753
|
+
el.load();
|
|
5754
|
+
} catch(_) {}
|
|
5755
|
+
} catch(_) {}
|
|
5756
|
+
}
|
|
5757
|
+
|
|
5758
|
+
function isYoutubeVideoElement(el) {
|
|
5759
|
+
if (!el || el.nodeType !== 1) return false;
|
|
5760
|
+
if ((el.tagName || '').toLowerCase() !== 'iframe') return false;
|
|
5761
|
+
if (el.hasAttribute && el.hasAttribute('data-youtube-id')) return true;
|
|
5762
|
+
var src = el.getAttribute('src') || '';
|
|
5763
|
+
return src.indexOf('youtube.com/embed/') !== -1 || src.indexOf('youtu.be/') !== -1;
|
|
5764
|
+
}
|
|
5765
|
+
|
|
5766
|
+
function normalizeYoutubeVideoId(input) {
|
|
5767
|
+
var raw = String(input || '').trim();
|
|
5768
|
+
if (!raw) return '';
|
|
5769
|
+
var m = raw.match(new RegExp('(?:youtube\\.com/(?:embed/|watch\\?(?:.*&)?v=|shorts/|live/)|youtu\\.be/)([A-Za-z0-9_-]{11})', 'i'));
|
|
5770
|
+
if (m) return m[1];
|
|
5771
|
+
var bare = raw.match(/^([A-Za-z0-9_-]{11})$/);
|
|
5772
|
+
return bare ? bare[1] : raw;
|
|
5773
|
+
}
|
|
5774
|
+
|
|
5775
|
+
function getYoutubeVideoId(el) {
|
|
5776
|
+
if (!isYoutubeVideoElement(el)) return '';
|
|
5777
|
+
try {
|
|
5778
|
+
var explicit = el.getAttribute('data-youtube-id');
|
|
5779
|
+
if (explicit != null && String(explicit).trim()) return String(explicit).trim();
|
|
5780
|
+
var src = el.getAttribute('src') || '';
|
|
5781
|
+
var m = src.match(new RegExp('(?:youtube\\.com/embed/|youtu\\.be/)([A-Za-z0-9_-]{11})', 'i'));
|
|
5782
|
+
return m ? m[1] : '';
|
|
5783
|
+
} catch(_) {
|
|
5784
|
+
return '';
|
|
5785
|
+
}
|
|
5786
|
+
}
|
|
5787
|
+
|
|
5788
|
+
function setYoutubeVideoId(el, value) {
|
|
5789
|
+
if (!el || el.nodeType !== 1) return;
|
|
5790
|
+
var id = normalizeYoutubeVideoId(value);
|
|
5791
|
+
try {
|
|
5792
|
+
if (id) {
|
|
5793
|
+
el.setAttribute('data-youtube-id', id);
|
|
5794
|
+
el.setAttribute('src', 'https://www.youtube.com/embed/' + id);
|
|
5795
|
+
} else {
|
|
5796
|
+
el.removeAttribute('data-youtube-id');
|
|
5797
|
+
el.setAttribute('src', 'about:blank');
|
|
5798
|
+
}
|
|
5799
|
+
} catch(_) {}
|
|
5800
|
+
}
|
|
5801
|
+
|
|
5802
|
+
function isVimeoVideoElement(el) {
|
|
5803
|
+
if (!el || el.nodeType !== 1) return false;
|
|
5804
|
+
if ((el.tagName || '').toLowerCase() !== 'iframe') return false;
|
|
5805
|
+
if (el.hasAttribute && el.hasAttribute('data-vimeo-id')) return true;
|
|
5806
|
+
var src = el.getAttribute('src') || '';
|
|
5807
|
+
return src.indexOf('player.vimeo.com/video/') !== -1 || src.indexOf('vimeo.com/video/') !== -1;
|
|
5808
|
+
}
|
|
5809
|
+
|
|
5810
|
+
function isEmbeddedVideoIframe(el) {
|
|
5811
|
+
return isYoutubeVideoElement(el) || isVimeoVideoElement(el);
|
|
5812
|
+
}
|
|
5813
|
+
|
|
5814
|
+
function normalizeVimeoVideoId(input) {
|
|
5815
|
+
var raw = String(input || '').trim();
|
|
5816
|
+
if (!raw) return '';
|
|
5817
|
+
var m = raw.match(new RegExp('(?:player\\.vimeo\\.com/video/|vimeo\\.com/(?:video/)?)([0-9]+)', 'i'));
|
|
5818
|
+
if (m) return m[1];
|
|
5819
|
+
var bare = raw.match(/^([0-9]+)$/);
|
|
5820
|
+
return bare ? bare[1] : raw.replace(/[^d]/g, '');
|
|
5821
|
+
}
|
|
5822
|
+
|
|
5823
|
+
function getVimeoVideoId(el) {
|
|
5824
|
+
if (!isVimeoVideoElement(el)) return '';
|
|
5825
|
+
try {
|
|
5826
|
+
var explicit = el.getAttribute('data-vimeo-id');
|
|
5827
|
+
if (explicit != null && String(explicit).trim()) return String(explicit).trim();
|
|
5828
|
+
var src = el.getAttribute('src') || '';
|
|
5829
|
+
var m = src.match(new RegExp('(?:player\\.vimeo\\.com/video/|vimeo\\.com/video/)([0-9]+)', 'i'));
|
|
5830
|
+
return m ? m[1] : '';
|
|
5831
|
+
} catch(_) {
|
|
5832
|
+
return '';
|
|
5833
|
+
}
|
|
5834
|
+
}
|
|
5835
|
+
|
|
5836
|
+
function setVimeoVideoId(el, value) {
|
|
5837
|
+
if (!el || el.nodeType !== 1) return;
|
|
5838
|
+
var id = normalizeVimeoVideoId(value);
|
|
5839
|
+
try {
|
|
5840
|
+
if (id) {
|
|
5841
|
+
el.setAttribute('data-vimeo-id', id);
|
|
5842
|
+
el.setAttribute('src', 'https://player.vimeo.com/video/' + id);
|
|
5843
|
+
} else {
|
|
5844
|
+
el.removeAttribute('data-vimeo-id');
|
|
5845
|
+
el.setAttribute('src', 'about:blank');
|
|
5846
|
+
}
|
|
5847
|
+
} catch(_) {}
|
|
5848
|
+
}
|
|
5849
|
+
|
|
5850
|
+
function buildAnchorContentFieldsHtml(el) {
|
|
5851
|
+
return (
|
|
5852
|
+
subLbl('Link attributes') +
|
|
5853
|
+
pr('Href', '<input class="pr-inp" id="pp-href" type="text" value="'+esc(el.getAttribute('href')||'')+'" placeholder="https:// or #section">') +
|
|
5854
|
+
pr2(
|
|
5855
|
+
'Target',
|
|
5856
|
+
'<select class="pr-inp" id="pp-target">'+selOpts(['','_self','_blank','_parent','_top'],el.getAttribute('target')||'')+'</select>',
|
|
5857
|
+
'Rel',
|
|
5858
|
+
'<input class="pr-inp" id="pp-rel" type="text" value="'+esc(el.getAttribute('rel')||'')+'" placeholder="noopener noreferrer">'
|
|
5859
|
+
) +
|
|
5860
|
+
pr2(
|
|
5861
|
+
'Download',
|
|
5862
|
+
'<input class="pr-inp" id="pp-download" type="text" value="'+esc(el.getAttribute('download')||'')+'" placeholder="filename">',
|
|
5863
|
+
'Title',
|
|
5864
|
+
'<input class="pr-inp" id="pp-link-title" type="text" value="'+esc(el.getAttribute('title')||'')+'">'
|
|
5865
|
+
) +
|
|
5866
|
+
pr2(
|
|
5867
|
+
'Hreflang',
|
|
5868
|
+
'<input class="pr-inp" id="pp-hreflang" type="text" value="'+esc(el.getAttribute('hreflang')||'')+'" placeholder="en">',
|
|
5869
|
+
'Type',
|
|
5870
|
+
'<input class="pr-inp" id="pp-link-type" type="text" value="'+esc(el.getAttribute('type')||'')+'" placeholder="MIME type">'
|
|
5871
|
+
) +
|
|
5872
|
+
pr(
|
|
5873
|
+
'Referrer policy',
|
|
5874
|
+
'<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>'
|
|
5875
|
+
)
|
|
5876
|
+
);
|
|
5877
|
+
}
|
|
5878
|
+
|
|
5879
|
+
function setOptionalAnchorAttr(el, name, value) {
|
|
5880
|
+
if (!el || !name) return;
|
|
5881
|
+
var v = value == null ? '' : String(value).trim();
|
|
5882
|
+
if (v) el.setAttribute(name, v);
|
|
5883
|
+
else el.removeAttribute(name);
|
|
5884
|
+
}
|
|
4818
5885
|
function openCustomCssModal() {
|
|
4819
5886
|
var modal = document.getElementById('custom-css-modal');
|
|
4820
5887
|
var ta = document.getElementById('custom-css-modal-textarea');
|
|
@@ -5040,7 +6107,7 @@ function renderRightPanel(el) {
|
|
|
5040
6107
|
|
|
5041
6108
|
// \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
|
|
5042
6109
|
document.getElementById('acc-body-typography').innerHTML =
|
|
5043
|
-
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:
|
|
6110
|
+
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>') +
|
|
5044
6111
|
pr2('Font size', '<input class="pr-inp" type="number" id="pp-fs" min="8" max="200" value="'+parseInt(cs.fontSize||'16')+'">',
|
|
5045
6112
|
'Font weight', '<select class="pr-inp" id="pp-fw">'+weightOpts(cs.fontWeight)+'</select>') +
|
|
5046
6113
|
pr('Font family', '<input class="pr-inp" id="pp-ff" type="text" value="'+esc(el.style.fontFamily||'')+'" placeholder="inherit">') +
|
|
@@ -5052,7 +6119,7 @@ function renderRightPanel(el) {
|
|
|
5052
6119
|
// \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
|
|
5053
6120
|
var bgiVal = (el.style.backgroundImage||'').replace(/url(['"]?([^'"]+)['"]?)/,'$1');
|
|
5054
6121
|
document.getElementById('acc-body-background').innerHTML =
|
|
5055
|
-
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:
|
|
6122
|
+
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>') +
|
|
5056
6123
|
pr('Image URL', '<input class="pr-inp" id="pp-bgi" type="url" value="'+esc(bgiVal)+'" placeholder="https://\u2026">') +
|
|
5057
6124
|
pr2('Size', '<select class="pr-inp" id="pp-bgs">'+selOpts(['auto','cover','contain'],el.style.backgroundSize||'auto')+'</select>',
|
|
5058
6125
|
'Repeat', '<select class="pr-inp" id="pp-bgr">'+selOpts(['repeat','no-repeat','repeat-x','repeat-y'],el.style.backgroundRepeat||'repeat')+'</select>');
|
|
@@ -5122,9 +6189,9 @@ function renderRightPanel(el) {
|
|
|
5122
6189
|
// \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
|
|
5123
6190
|
document.getElementById('acc-body-device').innerHTML =
|
|
5124
6191
|
subLbl('Mobile (\u2264768px)') +
|
|
5125
|
-
'<textarea class="pr-inp" id="pp-mob-css" style="width:100%;min-height:60px;font-family:
|
|
6192
|
+
'<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>' +
|
|
5126
6193
|
subLbl('Tablet (\u22641024px)') +
|
|
5127
|
-
'<textarea class="pr-inp" id="pp-tab-css" style="width:100%;min-height:60px;font-family:
|
|
6194
|
+
'<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>';
|
|
5128
6195
|
|
|
5129
6196
|
// \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
|
|
5130
6197
|
document.getElementById('acc-body-css').innerHTML =
|
|
@@ -5135,27 +6202,54 @@ function renderRightPanel(el) {
|
|
|
5135
6202
|
'<i class="bi bi-fullscreen"></i>' +
|
|
5136
6203
|
'</button>' +
|
|
5137
6204
|
'</div>' +
|
|
5138
|
-
'<textarea class="pr-inp" id="pp-css" style="width:100%;min-height:80px;font-family:
|
|
6205
|
+
'<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>';
|
|
5139
6206
|
|
|
5140
6207
|
// \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
|
|
5141
6208
|
var attrHtml =
|
|
5142
6209
|
pr('ID', '<input class="pr-inp" id="pp-id" type="text" value="'+esc(el.id||'')+'" placeholder="element-id">');
|
|
5143
|
-
if (tag==='a') attrHtml +=
|
|
5144
|
-
pr('Href', '<input class="pr-inp" id="pp-href" type="url" value="'+esc(el.getAttribute('href')||'')+'" placeholder="https://">') +
|
|
5145
|
-
pr('Target', '<select class="pr-inp" id="pp-target">'+selOpts(['','_blank','_self','_parent'],el.getAttribute('target')||'')+'</select>');
|
|
5146
6210
|
if (tag==='img') attrHtml +=
|
|
5147
6211
|
pr('Src', '<input class="pr-inp" id="pp-src" type="url" value="'+esc(el.getAttribute('src')||'')+'">') +
|
|
5148
6212
|
pr('Alt', '<input class="pr-inp" id="pp-alt" type="text" value="'+esc(el.getAttribute('alt')||'')+'">');
|
|
5149
|
-
if (tag==='
|
|
6213
|
+
if (tag==='textarea') attrHtml +=
|
|
5150
6214
|
pr('Placeholder', '<input class="pr-inp" id="pp-ph" type="text" value="'+esc(el.getAttribute('placeholder')||'')+'">');
|
|
5151
6215
|
document.getElementById('acc-body-attributes').innerHTML = attrHtml;
|
|
5152
6216
|
|
|
5153
6217
|
// \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
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
6218
|
+
var contentHtml = '';
|
|
6219
|
+
if (isLinkElement(el)) contentHtml += buildAnchorContentFieldsHtml(el);
|
|
6220
|
+
if (isFormControlElement(el)) {
|
|
6221
|
+
contentHtml +=
|
|
6222
|
+
subLbl('Value') +
|
|
6223
|
+
'<textarea class="pr-inp" id="pp-value" style="width:100%;min-height:44px;margin-bottom:8px">'+esc(getFormControlValue(el))+'</textarea>';
|
|
6224
|
+
}
|
|
6225
|
+
if (tag==='input') {
|
|
6226
|
+
contentHtml +=
|
|
6227
|
+
subLbl('Placeholder') +
|
|
6228
|
+
'<input class="pr-inp" id="pp-ph" type="text" value="'+esc(el.getAttribute('placeholder')||'')+'" style="width:100%;margin-bottom:8px">';
|
|
6229
|
+
}
|
|
6230
|
+
if (tag==='video') {
|
|
6231
|
+
contentHtml +=
|
|
6232
|
+
subLbl('Src') +
|
|
6233
|
+
'<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">';
|
|
6234
|
+
}
|
|
6235
|
+
if (isYoutubeVideoElement(el)) {
|
|
6236
|
+
contentHtml +=
|
|
6237
|
+
subLbl('YouTube video ID') +
|
|
6238
|
+
'<input class="pr-inp" id="pp-youtube-id" type="text" value="'+esc(getYoutubeVideoId(el))+'" placeholder="dQw4w9WgXcQ" style="width:100%;margin-bottom:8px">';
|
|
6239
|
+
}
|
|
6240
|
+
if (isVimeoVideoElement(el)) {
|
|
6241
|
+
contentHtml +=
|
|
6242
|
+
subLbl('Vimeo video ID') +
|
|
6243
|
+
'<input class="pr-inp" id="pp-vimeo-id" type="text" value="'+esc(getVimeoVideoId(el))+'" placeholder="76979871" style="width:100%;margin-bottom:8px">';
|
|
6244
|
+
}
|
|
6245
|
+
if (tag!=='input' && tag!=='video' && !isEmbeddedVideoIframe(el)) {
|
|
6246
|
+
contentHtml +=
|
|
6247
|
+
subLbl('Inner Text') +
|
|
6248
|
+
'<textarea class="pr-inp" id="pp-text" style="width:100%;min-height:60px;margin-bottom:8px">'+esc(el.innerText||'')+'</textarea>' +
|
|
6249
|
+
subLbl('Inner HTML') +
|
|
6250
|
+
'<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>';
|
|
6251
|
+
}
|
|
6252
|
+
document.getElementById('acc-body-content').innerHTML = contentHtml;
|
|
5159
6253
|
|
|
5160
6254
|
// \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
|
|
5161
6255
|
var bindings = [
|
|
@@ -5206,13 +6300,20 @@ function renderRightPanel(el) {
|
|
|
5206
6300
|
['pp-cls', function(v){el.className=v}],
|
|
5207
6301
|
['pp-css', function(v){el.setAttribute('style',v)}],
|
|
5208
6302
|
['pp-id', function(v){el.id=v}],
|
|
5209
|
-
['pp-href', function(v){el
|
|
5210
|
-
['pp-target', function(v){el
|
|
6303
|
+
['pp-href', function(v){setOptionalAnchorAttr(el,'href',v)}],
|
|
6304
|
+
['pp-target', function(v){setOptionalAnchorAttr(el,'target',v)}],
|
|
6305
|
+
['pp-rel', function(v){setOptionalAnchorAttr(el,'rel',v)}],
|
|
6306
|
+
['pp-download', function(v){setOptionalAnchorAttr(el,'download',v)}],
|
|
6307
|
+
['pp-link-title', function(v){setOptionalAnchorAttr(el,'title',v)}],
|
|
6308
|
+
['pp-hreflang', function(v){setOptionalAnchorAttr(el,'hreflang',v)}],
|
|
6309
|
+
['pp-link-type', function(v){setOptionalAnchorAttr(el,'type',v)}],
|
|
6310
|
+
['pp-referrerpolicy', function(v){setOptionalAnchorAttr(el,'referrerpolicy',v)}],
|
|
5211
6311
|
['pp-src', function(v){el.setAttribute('src',v)}],
|
|
6312
|
+
['pp-video-src', function(v){setVideoSrc(el, v)}],
|
|
6313
|
+
['pp-youtube-id', function(v){setYoutubeVideoId(el, v)}],
|
|
6314
|
+
['pp-vimeo-id', function(v){setVimeoVideoId(el, v)}],
|
|
5212
6315
|
['pp-alt', function(v){el.setAttribute('alt',v)}],
|
|
5213
6316
|
['pp-ph', function(v){el.setAttribute('placeholder',v)}],
|
|
5214
|
-
['pp-text', function(v){el.innerText=v}],
|
|
5215
|
-
['pp-html', function(v){el.innerHTML=v}],
|
|
5216
6317
|
];
|
|
5217
6318
|
var sel = buildSelector(el);
|
|
5218
6319
|
bindings.forEach(function(b){
|
|
@@ -5237,6 +6338,45 @@ function renderRightPanel(el) {
|
|
|
5237
6338
|
inp.addEventListener('change', onValueChange);
|
|
5238
6339
|
}
|
|
5239
6340
|
});
|
|
6341
|
+
wireContentFieldSync(el, sel);
|
|
6342
|
+
}
|
|
6343
|
+
|
|
6344
|
+
function wireContentFieldSync(el, sel) {
|
|
6345
|
+
var textInp = document.getElementById('pp-text');
|
|
6346
|
+
var htmlInp = document.getElementById('pp-html');
|
|
6347
|
+
var valueInp = document.getElementById('pp-value');
|
|
6348
|
+
var syncing = false;
|
|
6349
|
+
function applyContentChange(changedId) {
|
|
6350
|
+
if (syncing) return;
|
|
6351
|
+
syncing = true;
|
|
6352
|
+
try {
|
|
6353
|
+
var orig = getOriginalValue(changedId, el);
|
|
6354
|
+
if (changedId === 'pp-value') {
|
|
6355
|
+
el.value = valueInp.value;
|
|
6356
|
+
logChange(sel, 'pp-value', valueInp.value, el, orig);
|
|
6357
|
+
} else if (changedId === 'pp-text') {
|
|
6358
|
+
el.innerText = textInp.value;
|
|
6359
|
+
htmlInp.value = el.innerHTML;
|
|
6360
|
+
logChange(sel, 'pp-text', textInp.value, el, orig);
|
|
6361
|
+
} else {
|
|
6362
|
+
el.innerHTML = htmlInp.value;
|
|
6363
|
+
textInp.value = el.innerText;
|
|
6364
|
+
logChange(sel, 'pp-html', htmlInp.value, el, orig);
|
|
6365
|
+
}
|
|
6366
|
+
} finally {
|
|
6367
|
+
syncing = false;
|
|
6368
|
+
}
|
|
6369
|
+
}
|
|
6370
|
+
if (valueInp && isFormControlElement(el)) {
|
|
6371
|
+
valueInp.addEventListener('input', function() { applyContentChange('pp-value'); });
|
|
6372
|
+
valueInp.addEventListener('change', function() { applyContentChange('pp-value'); });
|
|
6373
|
+
}
|
|
6374
|
+
if (textInp && htmlInp) {
|
|
6375
|
+
textInp.addEventListener('input', function() { applyContentChange('pp-text'); });
|
|
6376
|
+
textInp.addEventListener('change', function() { applyContentChange('pp-text'); });
|
|
6377
|
+
htmlInp.addEventListener('input', function() { applyContentChange('pp-html'); });
|
|
6378
|
+
htmlInp.addEventListener('change', function() { applyContentChange('pp-html'); });
|
|
6379
|
+
}
|
|
5240
6380
|
}
|
|
5241
6381
|
|
|
5242
6382
|
// \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
|
|
@@ -5457,6 +6597,100 @@ function repositionDragSibling(dragEl, clientY) {
|
|
|
5457
6597
|
}
|
|
5458
6598
|
}
|
|
5459
6599
|
|
|
6600
|
+
function isMoveSwapSkippableSibling(el) {
|
|
6601
|
+
if (!el || el.nodeType !== 1) return true;
|
|
6602
|
+
if (isDomTreeSkippableTagName(el.tagName)) return true;
|
|
6603
|
+
try {
|
|
6604
|
+
if (el.hasAttribute && el.hasAttribute('hidden')) return true;
|
|
6605
|
+
if (el.getAttribute && el.getAttribute('data-vve-hidden') === '1') return true;
|
|
6606
|
+
} catch(_) {}
|
|
6607
|
+
try {
|
|
6608
|
+
if (el.style && el.style.display === 'none') return true;
|
|
6609
|
+
if (el.style && el.style.visibility === 'hidden') return true;
|
|
6610
|
+
} catch(_) {}
|
|
6611
|
+
try {
|
|
6612
|
+
var view = el.ownerDocument && el.ownerDocument.defaultView;
|
|
6613
|
+
var cs = view && view.getComputedStyle ? view.getComputedStyle(el) : null;
|
|
6614
|
+
if (cs && (cs.display === 'none' || cs.visibility === 'hidden')) return true;
|
|
6615
|
+
} catch(_) {}
|
|
6616
|
+
return false;
|
|
6617
|
+
}
|
|
6618
|
+
|
|
6619
|
+
function findMoveSwapSibling(el, direction) {
|
|
6620
|
+
if (!el) return null;
|
|
6621
|
+
var node = direction < 0 ? el.previousElementSibling : el.nextElementSibling;
|
|
6622
|
+
while (node && isMoveSwapSkippableSibling(node)) {
|
|
6623
|
+
node = direction < 0 ? node.previousElementSibling : node.nextElementSibling;
|
|
6624
|
+
}
|
|
6625
|
+
return node;
|
|
6626
|
+
}
|
|
6627
|
+
|
|
6628
|
+
function isMoveParentEscapeBlocked(parent) {
|
|
6629
|
+
if (!parent || parent.nodeType !== 1) return true;
|
|
6630
|
+
var tag = (parent.tagName || '').toLowerCase();
|
|
6631
|
+
if (tag === 'html' || tag === 'body') return true;
|
|
6632
|
+
try {
|
|
6633
|
+
var doc = parent.ownerDocument;
|
|
6634
|
+
if (doc && (parent === doc.documentElement || parent === doc.body)) return true;
|
|
6635
|
+
} catch(_) {}
|
|
6636
|
+
return false;
|
|
6637
|
+
}
|
|
6638
|
+
|
|
6639
|
+
/** When no visual sibling exists, lift the node to the grandparent (before/after its parent). */
|
|
6640
|
+
function canMoveEscapeToParent(el, direction) {
|
|
6641
|
+
if (!el || !el.parentElement) return false;
|
|
6642
|
+
var parent = el.parentElement;
|
|
6643
|
+
if (isMoveParentEscapeBlocked(parent) || !parent.parentElement) return false;
|
|
6644
|
+
if (findMoveSwapSibling(el, direction)) return false;
|
|
6645
|
+
return true;
|
|
6646
|
+
}
|
|
6647
|
+
|
|
6648
|
+
function canMoveElDirection(el, direction) {
|
|
6649
|
+
if (!el || !el.parentElement) return false;
|
|
6650
|
+
return !!findMoveSwapSibling(el, direction) || canMoveEscapeToParent(el, direction);
|
|
6651
|
+
}
|
|
6652
|
+
|
|
6653
|
+
function moveElByDirection(el, direction) {
|
|
6654
|
+
if (!el || !el.parentElement) return false;
|
|
6655
|
+
var parent = el.parentElement;
|
|
6656
|
+
var sibling = findMoveSwapSibling(el, direction);
|
|
6657
|
+
if (sibling) {
|
|
6658
|
+
if (direction < 0) parent.insertBefore(el, sibling);
|
|
6659
|
+
else parent.insertBefore(sibling, el);
|
|
6660
|
+
return true;
|
|
6661
|
+
}
|
|
6662
|
+
if (!canMoveEscapeToParent(el, direction)) return false;
|
|
6663
|
+
var grandparent = parent.parentElement;
|
|
6664
|
+
if (!grandparent) return false;
|
|
6665
|
+
if (direction < 0) grandparent.insertBefore(el, parent);
|
|
6666
|
+
else grandparent.insertBefore(el, parent.nextSibling);
|
|
6667
|
+
return true;
|
|
6668
|
+
}
|
|
6669
|
+
|
|
6670
|
+
function syncMoveFloaterButtons(el) {
|
|
6671
|
+
var upBtn = document.getElementById('sf-move-up');
|
|
6672
|
+
var downBtn = document.getElementById('sf-move-down');
|
|
6673
|
+
if (!upBtn || !downBtn) return;
|
|
6674
|
+
var canUp = canMoveElDirection(el, -1);
|
|
6675
|
+
var canDown = canMoveElDirection(el, 1);
|
|
6676
|
+
upBtn.disabled = !canUp;
|
|
6677
|
+
downBtn.disabled = !canDown;
|
|
6678
|
+
if (canUp) {
|
|
6679
|
+
upBtn.title = findMoveSwapSibling(el, -1)
|
|
6680
|
+
? 'Move up'
|
|
6681
|
+
: 'Move up (out of container)';
|
|
6682
|
+
} else {
|
|
6683
|
+
upBtn.title = 'Cannot move up';
|
|
6684
|
+
}
|
|
6685
|
+
if (canDown) {
|
|
6686
|
+
downBtn.title = findMoveSwapSibling(el, 1)
|
|
6687
|
+
? 'Move down'
|
|
6688
|
+
: 'Move down (out of container)';
|
|
6689
|
+
} else {
|
|
6690
|
+
downBtn.title = 'Cannot move down';
|
|
6691
|
+
}
|
|
6692
|
+
}
|
|
6693
|
+
|
|
5460
6694
|
function recordReorderAfterDrag(movedEl) {
|
|
5461
6695
|
if (!activeVarId || !movedEl || !movedEl.parentElement) return;
|
|
5462
6696
|
var prev = movedEl.previousElementSibling;
|
|
@@ -5485,13 +6719,11 @@ function recordReorderAfterDrag(movedEl) {
|
|
|
5485
6719
|
}
|
|
5486
6720
|
|
|
5487
6721
|
function moveSelectedElByDirection(direction) {
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
if (!
|
|
5492
|
-
|
|
5493
|
-
else p.insertBefore(sibling, selectedEl);
|
|
5494
|
-
recordReorderAfterDrag(selectedEl);
|
|
6722
|
+
var el = recoverSelectedElement(false) || selectedEl;
|
|
6723
|
+
if (!el || !el.parentElement) return;
|
|
6724
|
+
selectedEl = el;
|
|
6725
|
+
if (!moveElByDirection(el, direction)) return;
|
|
6726
|
+
recordReorderAfterDrag(el);
|
|
5495
6727
|
saveCurrentVariationHtml();
|
|
5496
6728
|
recomputeEditorDirty();
|
|
5497
6729
|
scheduleDomTreeRefresh();
|
|
@@ -5591,6 +6823,7 @@ function attachClickHandler() {
|
|
|
5591
6823
|
deselectElement(); return;
|
|
5592
6824
|
}
|
|
5593
6825
|
selectElement(target);
|
|
6826
|
+
if (currentMainTab !== 'design') switchMainTab('design');
|
|
5594
6827
|
}, true);
|
|
5595
6828
|
} catch(_) {}
|
|
5596
6829
|
}
|
|
@@ -5695,15 +6928,18 @@ function syncIframeInteractions(reason) {
|
|
|
5695
6928
|
// \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
|
|
5696
6929
|
/** Full snippets for Vvveb keys whose html field is placeholder text, not markup. */
|
|
5697
6930
|
var VVVEB_INSERT_HTML_OVERRIDES = {
|
|
5698
|
-
'html/gridrow': '<div
|
|
5699
|
-
'html/gridcolumn': '<div
|
|
5700
|
-
'html/container': '<div
|
|
5701
|
-
'html/btn-link': '<a
|
|
5702
|
-
'html/btn': '<button type="button"
|
|
5703
|
-
'html/
|
|
5704
|
-
'html/
|
|
5705
|
-
'html/
|
|
5706
|
-
'html/
|
|
6931
|
+
'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>',
|
|
6932
|
+
'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>',
|
|
6933
|
+
'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>',
|
|
6934
|
+
'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>',
|
|
6935
|
+
'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>',
|
|
6936
|
+
'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>',
|
|
6937
|
+
'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>',
|
|
6938
|
+
'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>',
|
|
6939
|
+
'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>',
|
|
6940
|
+
'html/breadcrumbitem': '<li style="display:inline;font-size:14px;color:#64748b"><a href="#" style="color:#2563eb;text-decoration:none">Item</a></li>',
|
|
6941
|
+
'html/listitem': '<li style="padding:10px 14px;font-size:14px;color:#334155;border:1px solid #e2e8f0;border-radius:6px;background:#fff">List item</li>',
|
|
6942
|
+
'html/tablebody': '<tbody><tr><td style="padding:10px 12px;border:1px solid #e2e8f0;font-size:14px">Cell</td></tr></tbody>',
|
|
5707
6943
|
};
|
|
5708
6944
|
|
|
5709
6945
|
function buildHtmlFromVvvebComponent(comp, typeKey) {
|
|
@@ -5731,7 +6967,7 @@ function insertVvvebComponent(typeKey) {
|
|
|
5731
6967
|
insertHtml(html);
|
|
5732
6968
|
}
|
|
5733
6969
|
|
|
5734
|
-
function insertHtml(html) {
|
|
6970
|
+
function insertHtml(html, options) {
|
|
5735
6971
|
if (!html) return;
|
|
5736
6972
|
try {
|
|
5737
6973
|
var iframe = document.getElementById('iframeId');
|
|
@@ -5759,7 +6995,17 @@ function insertHtml(html) {
|
|
|
5759
6995
|
} else {
|
|
5760
6996
|
doc.body.appendChild(frag);
|
|
5761
6997
|
}
|
|
6998
|
+
if (firstEl) {
|
|
6999
|
+
try {
|
|
7000
|
+
firstEl.setAttribute('data-vve-instance', generateVveInstanceId());
|
|
7001
|
+
} catch(_) {}
|
|
7002
|
+
htmlStr = firstEl.outerHTML;
|
|
7003
|
+
}
|
|
5762
7004
|
if (firstEl) selectElement(firstEl);
|
|
7005
|
+
var accSection = options && options.defaultAccSection;
|
|
7006
|
+
if (accSection) {
|
|
7007
|
+
requestAnimationFrame(function() { focusDesignAccordionSection(accSection); });
|
|
7008
|
+
}
|
|
5763
7009
|
if (activeVarId) {
|
|
5764
7010
|
var insertRow = {
|
|
5765
7011
|
selector: anchorSel,
|
|
@@ -5791,7 +7037,7 @@ function renderSidebar(filter) {
|
|
|
5791
7037
|
baseFiltered.forEach(function(c) {
|
|
5792
7038
|
var item = document.createElement('div'); item.className = 'cg-item'; item.title = 'Insert ' + c.name;
|
|
5793
7039
|
item.innerHTML = '<div class="cg-icon"><i class="bi ' + c.icon + '"></i></div><div class="cg-name">' + c.name + '</div>';
|
|
5794
|
-
item.onclick = function() { insertHtml(c.html); };
|
|
7040
|
+
item.onclick = function() { insertHtml(c.html, { defaultAccSection: c.defaultAccSection }); };
|
|
5795
7041
|
g1.appendChild(item);
|
|
5796
7042
|
});
|
|
5797
7043
|
compTab.appendChild(g1);
|
|
@@ -5831,7 +7077,7 @@ function renderSidebar(filter) {
|
|
|
5831
7077
|
var ch = document.createElement('div'); ch.className = 'cg-hdr'; ch.textContent = 'CRO Components'; secTab.appendChild(ch);
|
|
5832
7078
|
croFiltered.forEach(function(sec) {
|
|
5833
7079
|
var item = document.createElement('div'); item.className = 'sec-item';
|
|
5834
|
-
item.innerHTML = '<div class="sec-thumb">'+(sec
|
|
7080
|
+
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>';
|
|
5835
7081
|
item.onclick = function() { insertHtml(sec.html); };
|
|
5836
7082
|
secTab.appendChild(item);
|
|
5837
7083
|
});
|
|
@@ -5861,11 +7107,7 @@ document.getElementById('comp-search').addEventListener('input', function() {
|
|
|
5861
7107
|
});
|
|
5862
7108
|
var btnAddElement = document.getElementById('btn-add-element');
|
|
5863
7109
|
if (btnAddElement) {
|
|
5864
|
-
btnAddElement.addEventListener('click',
|
|
5865
|
-
e.preventDefault();
|
|
5866
|
-
e.stopPropagation();
|
|
5867
|
-
toggleSectionComponentsPanel();
|
|
5868
|
-
});
|
|
7110
|
+
btnAddElement.addEventListener('click', handleAddElementClick);
|
|
5869
7111
|
}
|
|
5870
7112
|
|
|
5871
7113
|
// \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
|
|
@@ -6070,13 +7312,19 @@ function bindLoadingTooltipPositioning() {
|
|
|
6070
7312
|
// \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
|
|
6071
7313
|
function registerCROSections() {
|
|
6072
7314
|
if (typeof Vvveb === 'undefined' || !Vvveb.Sections) return;
|
|
6073
|
-
CRO_SECTIONS.forEach(function(sec) {
|
|
7315
|
+
CRO_SECTIONS.forEach(function(sec) {
|
|
7316
|
+
Vvveb.Sections.add(sec.key, {
|
|
7317
|
+
name: sec.name,
|
|
7318
|
+
image: sec.image ? (CRO_SECTION_IMAGE_ROUTE + sec.image) : '',
|
|
7319
|
+
html: sec.html,
|
|
7320
|
+
});
|
|
7321
|
+
});
|
|
6074
7322
|
}
|
|
6075
7323
|
|
|
6076
7324
|
window.addEventListener('load', function() {
|
|
6077
7325
|
registerCROSections();
|
|
6078
7326
|
bindViewportControls();
|
|
6079
|
-
switchSectionComponentsTab(currentSectionComponentsTab);
|
|
7327
|
+
// switchSectionComponentsTab(currentSectionComponentsTab);
|
|
6080
7328
|
renderElementsTree(document.getElementById('comp-search').value);
|
|
6081
7329
|
vvvebReady = true;
|
|
6082
7330
|
bindLoadingTooltipPositioning();
|
|
@@ -6149,6 +7397,10 @@ window.addEventListener('load', function() {
|
|
|
6149
7397
|
syncIframeInteractions('iframe-load');
|
|
6150
7398
|
});
|
|
6151
7399
|
|
|
7400
|
+
var sfAdd = document.getElementById('sf-add');
|
|
7401
|
+
if (sfAdd) {
|
|
7402
|
+
sfAdd.addEventListener('click', handleAddElementClick);
|
|
7403
|
+
}
|
|
6152
7404
|
var sfMoveUp = document.getElementById('sf-move-up');
|
|
6153
7405
|
if (sfMoveUp) {
|
|
6154
7406
|
sfMoveUp.addEventListener('click', function(e) {
|
|
@@ -6248,6 +7500,20 @@ function createVisualEditorMiddleware(options) {
|
|
|
6248
7500
|
res.end(buildVvvebEditorHtml());
|
|
6249
7501
|
return;
|
|
6250
7502
|
}
|
|
7503
|
+
if (pathname.startsWith(CRO_SECTION_IMAGE_ROUTE)) {
|
|
7504
|
+
const filename = pathname.slice(CRO_SECTION_IMAGE_ROUTE.length);
|
|
7505
|
+
const filePath = resolveCroSectionImagePath(filename);
|
|
7506
|
+
if (!filePath) {
|
|
7507
|
+
res.statusCode = 404;
|
|
7508
|
+
res.end("Not found");
|
|
7509
|
+
return;
|
|
7510
|
+
}
|
|
7511
|
+
res.setHeader("Content-Type", "image/png");
|
|
7512
|
+
res.setHeader("Cache-Control", "public, max-age=86400");
|
|
7513
|
+
setFrameHeaders(req, res);
|
|
7514
|
+
res.end(fs.readFileSync(filePath));
|
|
7515
|
+
return;
|
|
7516
|
+
}
|
|
6251
7517
|
if (pathname === "/api/generate-test" && enableGenerateTestApi) {
|
|
6252
7518
|
if (req.method === "OPTIONS") {
|
|
6253
7519
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
@@ -6386,7 +7652,6 @@ function createVisualEditorMiddleware(options) {
|
|
|
6386
7652
|
const trackingMarkersForRequest = mergeTrackingMarkers(
|
|
6387
7653
|
extraTrackingMarkersForRequest
|
|
6388
7654
|
);
|
|
6389
|
-
console.log("trackingMarkersForRequest", trackingMarkersForRequest);
|
|
6390
7655
|
const strictFreezeParam = (url.searchParams.get("strictObserverFreeze") || "").toLowerCase();
|
|
6391
7656
|
const strictObserverFreezeForRequest = strictFreezeParam === "1" || strictFreezeParam === "true" || strictFreezeParam === "yes" ? true : strictFreezeParam === "0" || strictFreezeParam === "false" || strictFreezeParam === "no" ? false : strictObserverFreeze;
|
|
6392
7657
|
if (!targetUrl) {
|
|
@@ -7087,6 +8352,13 @@ function visualEditorProxyPlugin(options) {
|
|
|
7087
8352
|
generateBundle() {
|
|
7088
8353
|
this.emitFile({ type: "asset", fileName: "bridge.js", source: BRIDGE_SCRIPT });
|
|
7089
8354
|
this.emitFile({ type: "asset", fileName: "vvveb-editor/index.html", source: buildVvvebEditorHtml() });
|
|
8355
|
+
for (const imagePath of listCroSectionImageFiles()) {
|
|
8356
|
+
this.emitFile({
|
|
8357
|
+
type: "asset",
|
|
8358
|
+
fileName: path.join("images", "cro-sections", path.basename(imagePath)),
|
|
8359
|
+
source: fs.readFileSync(imagePath)
|
|
8360
|
+
});
|
|
8361
|
+
}
|
|
7090
8362
|
},
|
|
7091
8363
|
configureServer(server) {
|
|
7092
8364
|
server.middlewares.use(mw);
|