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