@accelerated-agency/visual-editor 0.5.3 → 0.5.5
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 +2047 -383
- package/dist/vite.js +2047 -383
- package/package.json +10 -2
- package/src/images/cro-sections/cro-cta-block.png +0 -0
- package/src/images/cro-sections/cro-exit-intent-bar.png +0 -0
- package/src/images/cro-sections/cro-feature-grid.png +0 -0
- package/src/images/cro-sections/cro-hero.png +0 -0
- package/src/images/cro-sections/cro-pricing-table.png +0 -0
- package/src/images/cro-sections/cro-social-proof.png +0 -0
- package/src/images/cro-sections/cro-trust-badges.png +0 -0
- package/src/images/cro-sections/cro-urgency-banner.png +0 -0
package/dist/vite.cjs
CHANGED
|
@@ -11,6 +11,108 @@ var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
|
11
11
|
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
12
12
|
|
|
13
13
|
// src/visualEditorProxyPlugin.ts
|
|
14
|
+
|
|
15
|
+
// src/croSections.ts
|
|
16
|
+
var CRO_SECTION_IMAGE_ROUTE = "/vvveb-editor-images/cro-sections/";
|
|
17
|
+
function croSectionImageFilename(key) {
|
|
18
|
+
return key.replace(/\//g, "-") + ".png";
|
|
19
|
+
}
|
|
20
|
+
var CRO_SECTIONS_BASE = [
|
|
21
|
+
{
|
|
22
|
+
key: "cro/hero",
|
|
23
|
+
name: "CRO Hero",
|
|
24
|
+
icon: "\u{1F3AF}",
|
|
25
|
+
desc: "High-converting hero section",
|
|
26
|
+
html: '<section style="background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);color:white;padding:80px 20px;text-align:center"><div style="max-width:700px;margin:0 auto"><h1 style="font-size:2.8rem;font-weight:800;margin-bottom:16px;color:white">Your Compelling Headline Here</h1><p style="font-size:1.15rem;margin-bottom:28px;opacity:0.9">A clear, benefit-focused subheadline that explains exactly what visitors get from you.</p><a href="#" style="display:inline-block;background:#f59e0b;color:white;padding:16px 40px;border-radius:6px;font-size:1.1rem;font-weight:700;text-decoration:none">Get Started Free →</a><p style="margin-top:14px;font-size:13px;opacity:0.65">✓ No credit card required · ✓ 14-day free trial</p></div></section>'
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
key: "cro/social-proof",
|
|
30
|
+
name: "Social Proof",
|
|
31
|
+
icon: "\u2B50",
|
|
32
|
+
desc: "Star rating + 3-column testimonials",
|
|
33
|
+
html: '<section style="padding:60px 20px;background:#f9fafb"><div style="max-width:1000px;margin:0 auto"><div style="text-align:center;margin-bottom:36px"><div style="font-size:2rem;color:#f59e0b;letter-spacing:4px">★★★★★</div><p style="font-weight:700;font-size:1.2rem;margin-top:4px">4.9 / 5 from 2,400+ verified reviews</p></div><div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:20px"><div style="background:white;border-radius:8px;padding:24px;box-shadow:0 1px 4px rgba(0,0,0,0.08)"><div style="color:#f59e0b;font-size:1.1rem;margin-bottom:10px">★★★★★</div><p style="font-size:14px;color:#444;margin-bottom:16px">"This product completely transformed our results. 40% increase in conversions within the first month."</p><div style="display:flex;align-items:center;gap:10px"><div style="width:36px;height:36px;border-radius:50%;background:#e0e7ff;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:14px">SJ</div><div><div style="font-weight:600;font-size:13px">Sarah Johnson</div><div style="font-size:11px;color:#888">VP Marketing, TechCorp</div></div></div></div><div style="background:white;border-radius:8px;padding:24px;box-shadow:0 1px 4px rgba(0,0,0,0.08)"><div style="color:#f59e0b;font-size:1.1rem;margin-bottom:10px">★★★★★</div><p style="font-size:14px;color:#444;margin-bottom:16px">"The ROI was immediate. Best investment we have made this year. Highly recommend to any serious marketer."</p><div style="display:flex;align-items:center;gap:10px"><div style="width:36px;height:36px;border-radius:50%;background:#dcfce7;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:14px">MC</div><div><div style="font-weight:600;font-size:13px">Mark Chen</div><div style="font-size:11px;color:#888">Founder, GrowthLabs</div></div></div></div><div style="background:white;border-radius:8px;padding:24px;box-shadow:0 1px 4px rgba(0,0,0,0.08)"><div style="color:#f59e0b;font-size:1.1rem;margin-bottom:10px">★★★★★</div><p style="font-size:14px;color:#444;margin-bottom:16px">"Incredible support and the product delivers exactly what it promises. Our entire team loves it."</p><div style="display:flex;align-items:center;gap:10px"><div style="width:36px;height:36px;border-radius:50%;background:#fee2e2;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:14px">AT</div><div><div style="font-weight:600;font-size:13px">Amanda Torres</div><div style="font-size:11px;color:#888">CMO, ScaleUp Inc</div></div></div></div></div></div></section>'
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
key: "cro/urgency-banner",
|
|
37
|
+
name: "Urgency Banner",
|
|
38
|
+
icon: "\u23F0",
|
|
39
|
+
desc: "Countdown timer + limited-time offer",
|
|
40
|
+
html: '<div style="background:#ef4444;color:white;text-align:center;padding:14px;font-size:14px;font-weight:500">🔥 Limited time offer: <strong>50% OFF</strong> ends in <span style="font-family:monospace;font-size:1rem;font-weight:700;background:rgba(0,0,0,0.2);padding:2px 10px;border-radius:4px;margin:0 6px">23:47:12</span>— <a href="#" style="color:white;font-weight:700;text-decoration:underline">Claim your discount →</a></div>'
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
key: "cro/trust-badges",
|
|
44
|
+
name: "Trust Badges",
|
|
45
|
+
icon: "\u{1F6E1}\uFE0F",
|
|
46
|
+
desc: "Security seals, payment icons, guarantees",
|
|
47
|
+
html: '<div style="padding:28px 20px;border-top:1px solid #e5e5e5;border-bottom:1px solid #e5e5e5;background:white"><div style="display:flex;flex-wrap:wrap;justify-content:center;align-items:center;gap:32px;max-width:700px;margin:0 auto"><div style="text-align:center;font-size:12px;color:#555"><div style="font-size:28px;margin-bottom:6px">🔒</div><div style="font-weight:600">SSL Secure</div><div style="font-size:10px;color:#888">256-bit encryption</div></div><div style="text-align:center;font-size:12px;color:#555"><div style="font-size:28px;margin-bottom:6px">↵</div><div style="font-weight:600">30-Day Guarantee</div><div style="font-size:10px;color:#888">Money back, no questions</div></div><div style="text-align:center;font-size:12px;color:#555"><div style="font-size:28px;margin-bottom:6px">⭐</div><div style="font-weight:600">4.9 / 5 Rating</div><div style="font-size:10px;color:#888">From 2,400+ reviews</div></div><div style="text-align:center;font-size:12px;color:#555"><div style="font-size:28px;margin-bottom:6px">💳</div><div style="font-weight:600">Secure Payment</div><div style="font-size:10px;color:#888">Visa · MC · PayPal</div></div></div></div>'
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
key: "cro/cta-block",
|
|
51
|
+
name: "CTA Block",
|
|
52
|
+
icon: "\u{1F4E3}",
|
|
53
|
+
desc: "Dark high-impact call-to-action section",
|
|
54
|
+
html: '<section style="background:#1a1a2e;color:white;padding:64px 20px;text-align:center"><div style="max-width:600px;margin:0 auto"><h2 style="font-size:2rem;font-weight:800;color:white;margin-bottom:10px">Ready to get started?</h2><p style="opacity:0.7;margin-bottom:32px">Join 10,000+ companies already seeing results with our platform.</p><div style="display:flex;gap:12px;justify-content:center;flex-wrap:wrap"><a href="#" style="display:inline-block;background:#f59e0b;color:white;padding:14px 36px;border-radius:6px;font-weight:700;text-decoration:none;font-size:1rem">Start Free Trial</a><a href="#" style="display:inline-block;border:2px solid rgba(255,255,255,0.4);color:white;padding:14px 36px;border-radius:6px;font-weight:600;text-decoration:none;font-size:1rem">Schedule Demo</a></div><p style="font-size:12px;margin-top:18px;opacity:0.45">No credit card required · Cancel anytime</p></div></section>'
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
key: "cro/feature-grid",
|
|
58
|
+
name: "Feature Grid",
|
|
59
|
+
icon: "\u2728",
|
|
60
|
+
desc: "3-column key benefits grid",
|
|
61
|
+
html: '<section style="padding:60px 20px;background:white"><div style="max-width:900px;margin:0 auto"><h2 style="text-align:center;font-size:1.8rem;font-weight:800;margin-bottom:48px">Why choose us?</h2><div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:32px;text-align:center"><div><div style="font-size:2.5rem;margin-bottom:14px">🚀</div><h5 style="font-weight:700;margin-bottom:8px">Fast Results</h5><p style="color:#666;font-size:14px">See improvements in your conversion rate within the first 30 days or your money back.</p></div><div><div style="font-size:2.5rem;margin-bottom:14px">📊</div><h5 style="font-weight:700;margin-bottom:8px">Data-Driven</h5><p style="color:#666;font-size:14px">Every decision backed by real user data and statistical significance testing.</p></div><div><div style="font-size:2.5rem;margin-bottom:14px">🎯</div><h5 style="font-weight:700;margin-bottom:8px">Precision Targeting</h5><p style="color:#666;font-size:14px">Target the right audience segments with personalized, high-converting experiences.</p></div></div></div></section>'
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
key: "cro/exit-intent-bar",
|
|
65
|
+
name: "Exit Intent Bar",
|
|
66
|
+
icon: "\u{1F6AA}",
|
|
67
|
+
desc: "Sticky bottom bar for exit-intent capture",
|
|
68
|
+
html: `<div style="position:fixed;bottom:0;left:0;right:0;background:#1e293b;color:white;padding:14px 20px;display:flex;align-items:center;justify-content:center;gap:16px;z-index:9999;box-shadow:0 -4px 20px rgba(0,0,0,0.2)"><span style="font-size:14px">🔔 <strong>Wait!</strong> Don't leave empty-handed — get 20% off your first order.</span><a href="#" style="background:#f59e0b;color:white;padding:8px 20px;border-radius:4px;font-weight:700;text-decoration:none;font-size:13px;white-space:nowrap">Claim Offer</a><a href="#" style="color:rgba(255,255,255,0.5);font-size:12px;text-decoration:none">No thanks</a></div>`
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
key: "cro/pricing-table",
|
|
72
|
+
name: "Pricing Table",
|
|
73
|
+
icon: "\u{1F4B0}",
|
|
74
|
+
desc: "3-tier pricing with highlighted plan",
|
|
75
|
+
html: '<section style="padding:60px 20px;background:#f8fafc"><div style="max-width:900px;margin:0 auto"><h2 style="text-align:center;font-weight:800;font-size:1.8rem;margin-bottom:8px">Simple, transparent pricing</h2><p style="text-align:center;color:#666;margin-bottom:48px">No hidden fees. Cancel anytime.</p><div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:20px"><div style="background:white;border:1px solid #e5e5e5;border-radius:10px;padding:28px"><h3 style="font-weight:700;margin-bottom:6px">Starter</h3><div style="font-size:2rem;font-weight:800;margin-bottom:16px">$29<span style="font-size:1rem;font-weight:400;color:#888">/mo</span></div><ul style="list-style:none;padding:0;font-size:14px;color:#555;margin-bottom:24px"><li style="padding:6px 0;border-bottom:1px solid #f0f0f0">✓ Up to 10,000 visitors/mo</li><li style="padding:6px 0;border-bottom:1px solid #f0f0f0">✓ 5 A/B tests</li><li style="padding:6px 0">✓ Email support</li></ul><a href="#" style="display:block;text-align:center;border:2px solid #e5e5e5;padding:10px;border-radius:6px;font-weight:600;text-decoration:none;color:#333">Get started</a></div><div style="background:#3b82f6;border-radius:10px;padding:28px;position:relative;transform:scale(1.04);box-shadow:0 8px 32px rgba(59,130,246,0.3)"><div style="position:absolute;top:-12px;left:50%;transform:translateX(-50%);background:#f59e0b;color:white;font-size:11px;font-weight:700;padding:4px 12px;border-radius:20px">MOST POPULAR</div><h3 style="font-weight:700;margin-bottom:6px;color:white">Pro</h3><div style="font-size:2rem;font-weight:800;margin-bottom:16px;color:white">$79<span style="font-size:1rem;font-weight:400;opacity:0.7">/mo</span></div><ul style="list-style:none;padding:0;font-size:14px;color:rgba(255,255,255,0.85);margin-bottom:24px"><li style="padding:6px 0;border-bottom:1px solid rgba(255,255,255,0.15)">✓ Up to 100,000 visitors/mo</li><li style="padding:6px 0;border-bottom:1px solid rgba(255,255,255,0.15)">✓ Unlimited A/B tests</li><li style="padding:6px 0">✓ Priority support</li></ul><a href="#" style="display:block;text-align:center;background:white;color:#3b82f6;padding:10px;border-radius:6px;font-weight:700;text-decoration:none">Get started</a></div><div style="background:white;border:1px solid #e5e5e5;border-radius:10px;padding:28px"><h3 style="font-weight:700;margin-bottom:6px">Enterprise</h3><div style="font-size:2rem;font-weight:800;margin-bottom:16px">Custom</div><ul style="list-style:none;padding:0;font-size:14px;color:#555;margin-bottom:24px"><li style="padding:6px 0;border-bottom:1px solid #f0f0f0">✓ Unlimited visitors</li><li style="padding:6px 0;border-bottom:1px solid #f0f0f0">✓ White-label option</li><li style="padding:6px 0">✓ Dedicated support</li></ul><a href="#" style="display:block;text-align:center;border:2px solid #e5e5e5;padding:10px;border-radius:6px;font-weight:600;text-decoration:none;color:#333">Contact sales</a></div></div></div></section>'
|
|
76
|
+
}
|
|
77
|
+
];
|
|
78
|
+
var CRO_SECTIONS = CRO_SECTIONS_BASE.map((section) => ({
|
|
79
|
+
...section,
|
|
80
|
+
image: croSectionImageFilename(section.key)
|
|
81
|
+
}));
|
|
82
|
+
|
|
83
|
+
// src/visualEditorProxyPlugin.ts
|
|
84
|
+
var PACKAGE_ROOT = path__default.default.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('vite.cjs', document.baseURI).href))));
|
|
85
|
+
function resolveCroSectionImagePath(filename) {
|
|
86
|
+
const safe = path__default.default.basename(filename);
|
|
87
|
+
if (!safe || safe !== filename) return null;
|
|
88
|
+
const candidates = [
|
|
89
|
+
path__default.default.join(PACKAGE_ROOT, "images", "cro-sections", safe),
|
|
90
|
+
path__default.default.join(PACKAGE_ROOT, "..", "src", "images", "cro-sections", safe),
|
|
91
|
+
path__default.default.join(process.cwd(), "src", "images", "cro-sections", safe)
|
|
92
|
+
];
|
|
93
|
+
for (const candidate of candidates) {
|
|
94
|
+
try {
|
|
95
|
+
if (fs__default.default.existsSync(candidate)) return candidate;
|
|
96
|
+
} catch (_) {
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
function listCroSectionImageFiles() {
|
|
102
|
+
const dirs = [
|
|
103
|
+
path__default.default.join(PACKAGE_ROOT, "images", "cro-sections"),
|
|
104
|
+
path__default.default.join(PACKAGE_ROOT, "..", "src", "images", "cro-sections"),
|
|
105
|
+
path__default.default.join(process.cwd(), "src", "images", "cro-sections")
|
|
106
|
+
];
|
|
107
|
+
for (const dir of dirs) {
|
|
108
|
+
try {
|
|
109
|
+
if (!fs__default.default.existsSync(dir)) continue;
|
|
110
|
+
return fs__default.default.readdirSync(dir).filter((name) => name.endsWith(".png")).map((name) => path__default.default.join(dir, name));
|
|
111
|
+
} catch (_) {
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return [];
|
|
115
|
+
}
|
|
14
116
|
var DEFAULT_TRACKING_MARKERS = [
|
|
15
117
|
"snowplow",
|
|
16
118
|
"taboola",
|
|
@@ -262,64 +364,6 @@ catch(_){}})();</script>`;
|
|
|
262
364
|
var AI_SYSTEM_PROMPT = `You are a CRO expert. Return JSON only with: hypothesis, mutations, summary. Keep 2-6 precise mutations and only valid selectors from snapshot.`;
|
|
263
365
|
var BRIDGE_SCRIPT = `(function(){if(window.__CONVERSION_BRIDGE_LOADED__)return;window.__CONVERSION_BRIDGE_LOADED__=true;var CHANNEL='conversion-editor';var highlightEl=null;function send(payload){window.parent.postMessage({channel:CHANNEL,payload:payload},'*');}function qs(selector){try{return document.querySelector(selector);}catch(_){return null;}}function getSelector(el){if(!el||el.nodeType!==1)return'';if(el.id)return'#'+CSS.escape(el.id);var parts=[];var current=el;var depth=0;while(current&¤t.nodeType===1&&depth<5){var part=current.tagName.toLowerCase();if(current.classList&¤t.classList.length){part+='.'+Array.from(current.classList).slice(0,2).map(function(c){return CSS.escape(c);}).join('.');}var parent=current.parentElement;if(parent){var siblings=Array.from(parent.children).filter(function(s){return s.tagName===current.tagName;});if(siblings.length>1)part+=':nth-of-type('+(siblings.indexOf(current)+1)+')';}parts.unshift(part);current=parent;depth+=1;}return parts.join(' > ');}function payloadOf(el){var rect=el.getBoundingClientRect();var style=window.getComputedStyle(el);return{selector:getSelector(el),tagName:el.tagName.toLowerCase(),textContent:(el.textContent||'').trim().slice(0,500),computedStyles:{color:style.color,backgroundColor:style.backgroundColor,fontSize:style.fontSize,fontWeight:style.fontWeight,lineHeight:style.lineHeight,display:style.display},rect:{top:rect.top,left:rect.left,width:rect.width,height:rect.height}};}function applyMutation(m){var el=qs(m.selector);if(!el)return;switch(m.action){case'setStyle':if(m.property)el.style[m.property]=m.value;break;case'setText':el.textContent=m.value;break;case'setHTML':el.innerHTML=m.value;break;case'setAttribute':if(m.property)el.setAttribute(m.property,m.value);break;case'hide':el.style.display='none';break;case'show':el.style.display='';break;case'insertHTML':if(m.position)el.insertAdjacentHTML(m.position,m.value||'');break;case'insertSection':if(m.position)el.insertAdjacentHTML(m.position,m.sectionHtml||m.value||'');break;case'reorderElement':if(!m.targetSelector)break;var target=qs(m.targetSelector);if(!target||!target.parentNode||!el.parentNode)break;if(m.insertPosition==='before')target.parentNode.insertBefore(el,target);else target.parentNode.insertBefore(el,target.nextSibling);break;default:break;}}function revertMutation(m){var el=qs(m.selector);if(!el)return;switch(m.action){case'setStyle':if(m.property)el.style[m.property]=m.previous||'';break;case'setText':el.textContent=m.previous||'';break;case'setHTML':el.innerHTML=m.previous||'';break;case'setAttribute':if(m.property){if(m.previous!=null)el.setAttribute(m.property,m.previous);else el.removeAttribute(m.property);}break;case'hide':case'show':el.style.display=m.previous||'';break;default:break;}}function captureSnapshot(){var elements=Array.from(document.querySelectorAll('h1,h2,h3,p,button,a,input,select,img,section,div')).slice(0,700).map(function(el){var rect=el.getBoundingClientRect();var cs=window.getComputedStyle(el);return{selector:getSelector(el),parentSelector:el.parentElement?getSelector(el.parentElement):null,tagName:el.tagName.toLowerCase(),textContent:(el.textContent||'').trim().slice(0,300),attributes:Array.from(el.attributes||[]).reduce(function(acc,a){acc[a.name]=a.value;return acc;},{}),computedStyles:{color:cs.color,backgroundColor:cs.backgroundColor,fontSize:cs.fontSize,fontWeight:cs.fontWeight,display:cs.display},childrenCount:el.children?el.children.length:0,aboveFold:rect.top<window.innerHeight,depth:(function(){var d=0,p=el.parentElement;while(p&&d<25){d++;p=p.parentElement;}return d;})()};});send({type:'snapshotCaptured',snapshot:{url:window.location.href,title:document.title,viewport:{width:window.innerWidth,height:window.innerHeight},elements:elements}});}function captureTree(){function toNode(el,depth){var rect=el.getBoundingClientRect();var tag=el.tagName.toLowerCase();var type='generic';if(tag==='section')type='section';else if(tag==='img')type='image';else if(tag==='a')type='link';else if(tag==='button')type='button';else if(tag==='form')type='form';else if(['p','h1','h2','h3','h4','h5','h6','span'].indexOf(tag)>=0)type='text';else if(['div','main','article','aside','header','footer','nav'].indexOf(tag)>=0)type='container';var children=Array.from(el.children||[]).slice(0,50).map(function(c){return toNode(c,depth+1);});return{id:getSelector(el),selector:getSelector(el),tagName:tag,label:(el.getAttribute('aria-label')||el.getAttribute('id')||el.className||tag).toString().slice(0,80),type:type,children:children,depth:depth,isAboveFold:rect.top<window.innerHeight,rect:{top:rect.top,left:rect.left,width:rect.width,height:rect.height}};}send({type:'pageTreeCaptured',tree:[toNode(document.body,0)]});}window.addEventListener('message',function(e){var msg=e.data;if(!msg||msg.channel!==CHANNEL||!msg.payload)return;var p=msg.payload;switch(p.type){case'ping':send({type:'pong'});break;case'applyMutation':applyMutation(p.mutation);break;case'applyMutationBatch':(p.mutations||[]).forEach(applyMutation);break;case'revert':revertMutation(p.mutation);break;case'clearAllMutations':window.location.reload();break;case'captureSnapshot':captureSnapshot();break;case'validateSelectors':send({type:'selectorsValidated',results:(p.selectors||[]).map(function(s){var el=qs(s);return{selector:s,found:!!el,tagName:el?el.tagName.toLowerCase():null};})});break;case'scrollToElement':case'selectElement':var target=qs(p.selector);if(target){target.scrollIntoView({behavior:'smooth',block:'center'});send({type:'elementSelected',element:payloadOf(target)});}break;case'hoverElement':var h=qs(p.selector);if(h){if(highlightEl)highlightEl.style.outline='';h.style.outline='2px solid #3b82f6';highlightEl=h;}break;case'capturePageTree':captureTree();break;default:break;}});document.addEventListener('click',function(e){var el=e.target;if(!(el instanceof Element))return;send({type:'elementSelected',element:payloadOf(el)});},true);send({type:'bridgeReady'});})();`;
|
|
264
366
|
function buildVvvebEditorHtml() {
|
|
265
|
-
const CRO_SECTIONS = [
|
|
266
|
-
{
|
|
267
|
-
key: "cro/hero",
|
|
268
|
-
name: "CRO Hero",
|
|
269
|
-
icon: "\u{1F3AF}",
|
|
270
|
-
desc: "High-converting hero section",
|
|
271
|
-
html: '<section style="background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);color:white;padding:80px 20px;text-align:center"><div style="max-width:700px;margin:0 auto"><h1 style="font-size:2.8rem;font-weight:800;margin-bottom:16px;color:white">Your Compelling Headline Here</h1><p style="font-size:1.15rem;margin-bottom:28px;opacity:0.9">A clear, benefit-focused subheadline that explains exactly what visitors get from you.</p><a href="#" style="display:inline-block;background:#f59e0b;color:white;padding:16px 40px;border-radius:6px;font-size:1.1rem;font-weight:700;text-decoration:none">Get Started Free →</a><p style="margin-top:14px;font-size:13px;opacity:0.65">✓ No credit card required · ✓ 14-day free trial</p></div></section>'
|
|
272
|
-
},
|
|
273
|
-
{
|
|
274
|
-
key: "cro/social-proof",
|
|
275
|
-
name: "Social Proof",
|
|
276
|
-
icon: "\u2B50",
|
|
277
|
-
desc: "Star rating + 3-column testimonials",
|
|
278
|
-
html: '<section style="padding:60px 20px;background:#f9fafb"><div style="max-width:1000px;margin:0 auto"><div style="text-align:center;margin-bottom:36px"><div style="font-size:2rem;color:#f59e0b;letter-spacing:4px">★★★★★</div><p style="font-weight:700;font-size:1.2rem;margin-top:4px">4.9 / 5 from 2,400+ verified reviews</p></div><div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:20px"><div style="background:white;border-radius:8px;padding:24px;box-shadow:0 1px 4px rgba(0,0,0,0.08)"><div style="color:#f59e0b;font-size:1.1rem;margin-bottom:10px">★★★★★</div><p style="font-size:14px;color:#444;margin-bottom:16px">"This product completely transformed our results. 40% increase in conversions within the first month."</p><div style="display:flex;align-items:center;gap:10px"><div style="width:36px;height:36px;border-radius:50%;background:#e0e7ff;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:14px">SJ</div><div><div style="font-weight:600;font-size:13px">Sarah Johnson</div><div style="font-size:11px;color:#888">VP Marketing, TechCorp</div></div></div></div><div style="background:white;border-radius:8px;padding:24px;box-shadow:0 1px 4px rgba(0,0,0,0.08)"><div style="color:#f59e0b;font-size:1.1rem;margin-bottom:10px">★★★★★</div><p style="font-size:14px;color:#444;margin-bottom:16px">"The ROI was immediate. Best investment we have made this year. Highly recommend to any serious marketer."</p><div style="display:flex;align-items:center;gap:10px"><div style="width:36px;height:36px;border-radius:50%;background:#dcfce7;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:14px">MC</div><div><div style="font-weight:600;font-size:13px">Mark Chen</div><div style="font-size:11px;color:#888">Founder, GrowthLabs</div></div></div></div><div style="background:white;border-radius:8px;padding:24px;box-shadow:0 1px 4px rgba(0,0,0,0.08)"><div style="color:#f59e0b;font-size:1.1rem;margin-bottom:10px">★★★★★</div><p style="font-size:14px;color:#444;margin-bottom:16px">"Incredible support and the product delivers exactly what it promises. Our entire team loves it."</p><div style="display:flex;align-items:center;gap:10px"><div style="width:36px;height:36px;border-radius:50%;background:#fee2e2;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:14px">AT</div><div><div style="font-weight:600;font-size:13px">Amanda Torres</div><div style="font-size:11px;color:#888">CMO, ScaleUp Inc</div></div></div></div></div></div></section>'
|
|
279
|
-
},
|
|
280
|
-
{
|
|
281
|
-
key: "cro/urgency-banner",
|
|
282
|
-
name: "Urgency Banner",
|
|
283
|
-
icon: "\u23F0",
|
|
284
|
-
desc: "Countdown timer + limited-time offer",
|
|
285
|
-
html: '<div style="background:#ef4444;color:white;text-align:center;padding:14px;font-size:14px;font-weight:500">🔥 Limited time offer: <strong>50% OFF</strong> ends in <span style="font-family:monospace;font-size:1rem;font-weight:700;background:rgba(0,0,0,0.2);padding:2px 10px;border-radius:4px;margin:0 6px">23:47:12</span>— <a href="#" style="color:white;font-weight:700;text-decoration:underline">Claim your discount →</a></div>'
|
|
286
|
-
},
|
|
287
|
-
{
|
|
288
|
-
key: "cro/trust-badges",
|
|
289
|
-
name: "Trust Badges",
|
|
290
|
-
icon: "\u{1F6E1}\uFE0F",
|
|
291
|
-
desc: "Security seals, payment icons, guarantees",
|
|
292
|
-
html: '<div style="padding:28px 20px;border-top:1px solid #e5e5e5;border-bottom:1px solid #e5e5e5;background:white"><div style="display:flex;flex-wrap:wrap;justify-content:center;align-items:center;gap:32px;max-width:700px;margin:0 auto"><div style="text-align:center;font-size:12px;color:#555"><div style="font-size:28px;margin-bottom:6px">🔒</div><div style="font-weight:600">SSL Secure</div><div style="font-size:10px;color:#888">256-bit encryption</div></div><div style="text-align:center;font-size:12px;color:#555"><div style="font-size:28px;margin-bottom:6px">↵</div><div style="font-weight:600">30-Day Guarantee</div><div style="font-size:10px;color:#888">Money back, no questions</div></div><div style="text-align:center;font-size:12px;color:#555"><div style="font-size:28px;margin-bottom:6px">⭐</div><div style="font-weight:600">4.9 / 5 Rating</div><div style="font-size:10px;color:#888">From 2,400+ reviews</div></div><div style="text-align:center;font-size:12px;color:#555"><div style="font-size:28px;margin-bottom:6px">💳</div><div style="font-weight:600">Secure Payment</div><div style="font-size:10px;color:#888">Visa · MC · PayPal</div></div></div></div>'
|
|
293
|
-
},
|
|
294
|
-
{
|
|
295
|
-
key: "cro/cta-block",
|
|
296
|
-
name: "CTA Block",
|
|
297
|
-
icon: "\u{1F4E3}",
|
|
298
|
-
desc: "Dark high-impact call-to-action section",
|
|
299
|
-
html: '<section style="background:#1a1a2e;color:white;padding:64px 20px;text-align:center"><div style="max-width:600px;margin:0 auto"><h2 style="font-size:2rem;font-weight:800;color:white;margin-bottom:10px">Ready to get started?</h2><p style="opacity:0.7;margin-bottom:32px">Join 10,000+ companies already seeing results with our platform.</p><div style="display:flex;gap:12px;justify-content:center;flex-wrap:wrap"><a href="#" style="display:inline-block;background:#f59e0b;color:white;padding:14px 36px;border-radius:6px;font-weight:700;text-decoration:none;font-size:1rem">Start Free Trial</a><a href="#" style="display:inline-block;border:2px solid rgba(255,255,255,0.4);color:white;padding:14px 36px;border-radius:6px;font-weight:600;text-decoration:none;font-size:1rem">Schedule Demo</a></div><p style="font-size:12px;margin-top:18px;opacity:0.45">No credit card required · Cancel anytime</p></div></section>'
|
|
300
|
-
},
|
|
301
|
-
{
|
|
302
|
-
key: "cro/feature-grid",
|
|
303
|
-
name: "Feature Grid",
|
|
304
|
-
icon: "\u2728",
|
|
305
|
-
desc: "3-column key benefits grid",
|
|
306
|
-
html: '<section style="padding:60px 20px;background:white"><div style="max-width:900px;margin:0 auto"><h2 style="text-align:center;font-size:1.8rem;font-weight:800;margin-bottom:48px">Why choose us?</h2><div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:32px;text-align:center"><div><div style="font-size:2.5rem;margin-bottom:14px">🚀</div><h5 style="font-weight:700;margin-bottom:8px">Fast Results</h5><p style="color:#666;font-size:14px">See improvements in your conversion rate within the first 30 days or your money back.</p></div><div><div style="font-size:2.5rem;margin-bottom:14px">📊</div><h5 style="font-weight:700;margin-bottom:8px">Data-Driven</h5><p style="color:#666;font-size:14px">Every decision backed by real user data and statistical significance testing.</p></div><div><div style="font-size:2.5rem;margin-bottom:14px">🎯</div><h5 style="font-weight:700;margin-bottom:8px">Precision Targeting</h5><p style="color:#666;font-size:14px">Target the right audience segments with personalized, high-converting experiences.</p></div></div></div></section>'
|
|
307
|
-
},
|
|
308
|
-
{
|
|
309
|
-
key: "cro/exit-intent-bar",
|
|
310
|
-
name: "Exit Intent Bar",
|
|
311
|
-
icon: "\u{1F6AA}",
|
|
312
|
-
desc: "Sticky bottom bar for exit-intent capture",
|
|
313
|
-
html: `<div style="position:fixed;bottom:0;left:0;right:0;background:#1e293b;color:white;padding:14px 20px;display:flex;align-items:center;justify-content:center;gap:16px;z-index:9999;box-shadow:0 -4px 20px rgba(0,0,0,0.2)"><span style="font-size:14px">🔔 <strong>Wait!</strong> Don't leave empty-handed — get 20% off your first order.</span><a href="#" style="background:#f59e0b;color:white;padding:8px 20px;border-radius:4px;font-weight:700;text-decoration:none;font-size:13px;white-space:nowrap">Claim Offer</a><a href="#" style="color:rgba(255,255,255,0.5);font-size:12px;text-decoration:none">No thanks</a></div>`
|
|
314
|
-
},
|
|
315
|
-
{
|
|
316
|
-
key: "cro/pricing-table",
|
|
317
|
-
name: "Pricing Table",
|
|
318
|
-
icon: "\u{1F4B0}",
|
|
319
|
-
desc: "3-tier pricing with highlighted plan",
|
|
320
|
-
html: '<section style="padding:60px 20px;background:#f8fafc"><div style="max-width:900px;margin:0 auto"><h2 style="text-align:center;font-weight:800;font-size:1.8rem;margin-bottom:8px">Simple, transparent pricing</h2><p style="text-align:center;color:#666;margin-bottom:48px">No hidden fees. Cancel anytime.</p><div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:20px"><div style="background:white;border:1px solid #e5e5e5;border-radius:10px;padding:28px"><h3 style="font-weight:700;margin-bottom:6px">Starter</h3><div style="font-size:2rem;font-weight:800;margin-bottom:16px">$29<span style="font-size:1rem;font-weight:400;color:#888">/mo</span></div><ul style="list-style:none;padding:0;font-size:14px;color:#555;margin-bottom:24px"><li style="padding:6px 0;border-bottom:1px solid #f0f0f0">✓ Up to 10,000 visitors/mo</li><li style="padding:6px 0;border-bottom:1px solid #f0f0f0">✓ 5 A/B tests</li><li style="padding:6px 0">✓ Email support</li></ul><a href="#" style="display:block;text-align:center;border:2px solid #e5e5e5;padding:10px;border-radius:6px;font-weight:600;text-decoration:none;color:#333">Get started</a></div><div style="background:#3b82f6;border-radius:10px;padding:28px;position:relative;transform:scale(1.04);box-shadow:0 8px 32px rgba(59,130,246,0.3)"><div style="position:absolute;top:-12px;left:50%;transform:translateX(-50%);background:#f59e0b;color:white;font-size:11px;font-weight:700;padding:4px 12px;border-radius:20px">MOST POPULAR</div><h3 style="font-weight:700;margin-bottom:6px;color:white">Pro</h3><div style="font-size:2rem;font-weight:800;margin-bottom:16px;color:white">$79<span style="font-size:1rem;font-weight:400;opacity:0.7">/mo</span></div><ul style="list-style:none;padding:0;font-size:14px;color:rgba(255,255,255,0.85);margin-bottom:24px"><li style="padding:6px 0;border-bottom:1px solid rgba(255,255,255,0.15)">✓ Up to 100,000 visitors/mo</li><li style="padding:6px 0;border-bottom:1px solid rgba(255,255,255,0.15)">✓ Unlimited A/B tests</li><li style="padding:6px 0">✓ Priority support</li></ul><a href="#" style="display:block;text-align:center;background:white;color:#3b82f6;padding:10px;border-radius:6px;font-weight:700;text-decoration:none">Get started</a></div><div style="background:white;border:1px solid #e5e5e5;border-radius:10px;padding:28px"><h3 style="font-weight:700;margin-bottom:6px">Enterprise</h3><div style="font-size:2rem;font-weight:800;margin-bottom:16px">Custom</div><ul style="list-style:none;padding:0;font-size:14px;color:#555;margin-bottom:24px"><li style="padding:6px 0;border-bottom:1px solid #f0f0f0">✓ Unlimited visitors</li><li style="padding:6px 0;border-bottom:1px solid #f0f0f0">✓ White-label option</li><li style="padding:6px 0">✓ Dedicated support</li></ul><a href="#" style="display:block;text-align:center;border:2px solid #e5e5e5;padding:10px;border-radius:6px;font-weight:600;text-decoration:none;color:#333">Contact sales</a></div></div></div></section>'
|
|
321
|
-
}
|
|
322
|
-
];
|
|
323
367
|
const sectionsJson = JSON.stringify(CRO_SECTIONS);
|
|
324
368
|
return `<!DOCTYPE html>
|
|
325
369
|
<html lang="en">
|
|
@@ -327,27 +371,39 @@ function buildVvvebEditorHtml() {
|
|
|
327
371
|
<meta charset="UTF-8">
|
|
328
372
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
329
373
|
<title>Visual Editor V2</title>
|
|
374
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
375
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
376
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">
|
|
330
377
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
|
331
378
|
<style>
|
|
332
379
|
/* \u2500\u2500 Reset \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
333
380
|
*{box-sizing:border-box;margin:0;padding:0}
|
|
334
|
-
html,body{height:100%;overflow:hidden;font-family
|
|
381
|
+
html,body{height:100%;overflow:hidden;font-family:var(--font-sans);font-size:13px;color:#1e293b;background:#f1f5f9}
|
|
335
382
|
|
|
336
383
|
/* \u2500\u2500 CSS variables \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
337
384
|
:root{
|
|
385
|
+
--font-inter:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
|
|
386
|
+
--font-roboto:'Roboto',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
|
|
387
|
+
--font-mono:'JetBrains Mono',ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;
|
|
388
|
+
--font-sans:var(--font-inter),var(--font-roboto),-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
|
|
338
389
|
--bg: #ffffff;
|
|
339
390
|
--bg-sub: #f8fafc;
|
|
340
|
-
--bg-hover: #
|
|
391
|
+
--bg-hover: #F5F5F5;
|
|
341
392
|
--border: #e2e8f0;
|
|
342
393
|
--border-sub: #f1f5f9;
|
|
343
394
|
--text: #404040;
|
|
344
395
|
--text-2: #475569;
|
|
345
396
|
--text-3: #94a3b8;
|
|
346
|
-
--accent: #
|
|
347
|
-
--accent-bg: #
|
|
397
|
+
--accent: #262626;
|
|
398
|
+
--accent-bg: #f5f5f5;
|
|
348
399
|
--accent-txt: #404040;
|
|
349
400
|
}
|
|
350
401
|
|
|
402
|
+
/* \u2500\u2500 Font utilities \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
403
|
+
.inter{font-family:var(--font-inter)}
|
|
404
|
+
.roboto{font-family:var(--font-roboto)}
|
|
405
|
+
.mono{font-family:var(--font-mono)}
|
|
406
|
+
|
|
351
407
|
/* \u2500\u2500 Layout \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
352
408
|
#app{display:flex;flex-direction:column;height:100vh}
|
|
353
409
|
#main{display:flex;flex:1;overflow:hidden;min-height:0}
|
|
@@ -425,9 +481,32 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
425
481
|
border-color:transparent;
|
|
426
482
|
}
|
|
427
483
|
.tb-dev-menu input#dev-zoom-level{
|
|
428
|
-
max-width:
|
|
429
|
-
margin-left:
|
|
484
|
+
max-width:72px;
|
|
485
|
+
margin-left:0;
|
|
430
486
|
}
|
|
487
|
+
.tb-dev-menu .row-zoom .zoom-controls{
|
|
488
|
+
display:flex;
|
|
489
|
+
align-items:center;
|
|
490
|
+
gap:6px;
|
|
491
|
+
margin-left:auto;
|
|
492
|
+
}
|
|
493
|
+
.tb-dev-menu .dev-zoom-fit-btn{
|
|
494
|
+
width:30px;
|
|
495
|
+
height:30px;
|
|
496
|
+
flex-shrink:0;
|
|
497
|
+
border:none;
|
|
498
|
+
border-radius:6px;
|
|
499
|
+
background:#fff;
|
|
500
|
+
cursor:pointer;
|
|
501
|
+
display:flex;
|
|
502
|
+
align-items:center;
|
|
503
|
+
justify-content:center;
|
|
504
|
+
color:#404040;
|
|
505
|
+
box-shadow:0 0 1px 0 rgba(0,0,0,.20),0 1px 2px 0 rgba(0,0,0,.05),0 1px 1px 0 rgba(0,0,0,.01);
|
|
506
|
+
transition:background .12s,color .12s;
|
|
507
|
+
}
|
|
508
|
+
.tb-dev-menu .dev-zoom-fit-btn:hover{background:#f4f4f5;color:#171717}
|
|
509
|
+
.tb-dev-menu .dev-zoom-fit-btn svg{display:block;width:16px;height:16px}
|
|
431
510
|
.tb-dev-menu input:focus{
|
|
432
511
|
border-color:#1A1A1A;
|
|
433
512
|
box-shadow:0 0 0 2px rgba(99,102,241,.14)
|
|
@@ -457,19 +536,10 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
457
536
|
text-overflow: ellipsis;
|
|
458
537
|
font-size: var(--font-size-sm, 14px);
|
|
459
538
|
font-style: normal;
|
|
460
|
-
font-weight: 500
|
|
539
|
+
font-weight: 500;#
|
|
461
540
|
line-height: var(--font-leading-4, 16px);
|
|
462
541
|
}
|
|
463
542
|
.tb-dev-menu .vp-preset-btn:hover,.tb-dev-menu .vp-preset-btn.active{background:#f4f4f5}
|
|
464
|
-
.tb-dev-menu .ft{
|
|
465
|
-
margin-top:10px;padding-top:8px;border-top:1px solid #ececf0;
|
|
466
|
-
display:flex;justify-content:flex-end
|
|
467
|
-
}
|
|
468
|
-
.tb-dev-menu .apply-btn{
|
|
469
|
-
border:1px solid #d4d4d8;background:#f8fafc;color:#111827;border-radius:6px;
|
|
470
|
-
height:30px;padding:0 10px;font-size:12px;font-weight:600;cursor:pointer
|
|
471
|
-
}
|
|
472
|
-
.tb-dev-menu .apply-btn:hover{background:#eef2ff;border-color:#a5b4fc}
|
|
473
543
|
/* Dark icon buttons */
|
|
474
544
|
.tb-dk-btn{width:28px;height:28px;background:transparent;border:none;border-radius:5px;cursor:pointer;color:#71717a;display:flex;align-items:center;justify-content:center;font-size:13px;transition:all .12s;flex-shrink:0}
|
|
475
545
|
.tb-dk-btn:hover{color:#e4e4e7;background:rgba(255,255,255,.07)}
|
|
@@ -500,9 +570,29 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
500
570
|
.tb-sim-btn{background:transparent;border:1px solid #e5e7eb;border-radius:6px;color:#404040;cursor:pointer;font-size:14px;font-weight:500;padding:6px 10px;display:flex;align-items:center;gap:5px;transition:all .15s;white-space:nowrap;font-family:inherit}
|
|
501
571
|
.tb-sim-btn:hover{background:rgba(255,255,255,.06);border-color:#52525b}
|
|
502
572
|
.tb-sim-btn i{font-size:11px}
|
|
503
|
-
.tb-fin-btn{
|
|
504
|
-
|
|
505
|
-
|
|
573
|
+
.tb-fin-btn{ border: none;
|
|
574
|
+
cursor: pointer;
|
|
575
|
+
transition: all .15s;
|
|
576
|
+
white-space: nowrap;
|
|
577
|
+
border-radius: var(--radius-md, 6px);
|
|
578
|
+
background: var(--bg-primary-default, #262626);
|
|
579
|
+
padding: 7px 10px;
|
|
580
|
+
color: var(--content-on-color, #FFF);
|
|
581
|
+
text-align: center;
|
|
582
|
+
font-family: Inter;
|
|
583
|
+
font-size: var(--font-size-sm, 14px);
|
|
584
|
+
font-style: normal;
|
|
585
|
+
font-weight: 500;
|
|
586
|
+
line-height: var(--font-leading-4, 16px);
|
|
587
|
+
}
|
|
588
|
+
.tb-fin-btn:hover{opacity:0.8;}
|
|
589
|
+
.tb-fin-btn#btn-save{
|
|
590
|
+
background: var(--bg-interactive-default, #FFF);
|
|
591
|
+
box-shadow: 0 0 1px 0 var(--Black-20, rgba(0, 0, 0, 0.20)), 0 1px 2px 0 var(--Black-5, rgba(0, 0, 0, 0.05)), 0 1px 1px 0 rgba(0, 0, 0, 0.01);
|
|
592
|
+
border: none;
|
|
593
|
+
color: var(--content-success-default, #00C951);
|
|
594
|
+
font-weight: 500;
|
|
595
|
+
}
|
|
506
596
|
/* \u2500\u2500 Page loading hint (toolbar + sidebar) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
507
597
|
.tb-page-loading{
|
|
508
598
|
display:none;flex-shrink:0;align-items:center;margin:0 10px 0 4px;
|
|
@@ -559,14 +649,17 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
559
649
|
|
|
560
650
|
/* \u2500\u2500 Left panel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
561
651
|
#left-panel{
|
|
562
|
-
width:
|
|
563
|
-
display:flex;flex-direction:column;flex-shrink:0;min-height:0;overflow:hidden
|
|
652
|
+
width:288px;
|
|
653
|
+
display:flex;flex-direction:column;flex-shrink:0;min-height:0;overflow:hidden;
|
|
654
|
+
border-right: 1px solid var(--border-default, #E5E5E5);
|
|
655
|
+
background: var(--cu-Background-Main, #FFF);
|
|
564
656
|
}
|
|
565
657
|
|
|
566
658
|
/* \u2500\u2500 Iframe panel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
567
659
|
#iframe-panel{
|
|
568
660
|
flex:1;background:#e8ecf0;display:flex;flex-direction:column;
|
|
569
|
-
align-items:center;justify-content:flex-start;overflow:
|
|
661
|
+
align-items:center;justify-content:flex-start;overflow:hidden;position:relative;
|
|
662
|
+
min-height:0;min-width:0
|
|
570
663
|
}
|
|
571
664
|
|
|
572
665
|
/* \u2500\u2500 Floating selection toolbar (above iframe selection) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
@@ -587,13 +680,34 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
587
680
|
#selection-floater .sf-sep{width:1px;height:16px;background:var(--border);margin:0 2px;flex-shrink:0}
|
|
588
681
|
|
|
589
682
|
/* \u2500\u2500 DOM tree (Elements tab) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
590
|
-
.dt-tree{
|
|
683
|
+
.dt-tree{user-select:none}
|
|
591
684
|
.dt-row{
|
|
592
|
-
|
|
593
|
-
|
|
685
|
+
width: 100%;
|
|
686
|
+
display: flex;
|
|
687
|
+
align-items: center;
|
|
688
|
+
gap: 2px;
|
|
689
|
+
min-height: 26px;
|
|
690
|
+
padding: 10px 8px 10px 4px;
|
|
691
|
+
cursor: pointer;
|
|
692
|
+
color: var(--text-2);
|
|
693
|
+
position: relative;
|
|
594
694
|
}
|
|
595
695
|
.dt-row:hover{background:var(--bg-hover);color:var(--text)}
|
|
596
|
-
.dt-row.dt-selected{background
|
|
696
|
+
.dt-row.dt-selected{position:relative;background:var(--bg-hover);}
|
|
697
|
+
.dt-row.dt-selected::before, .dt-row:hover::before{
|
|
698
|
+
display: block;
|
|
699
|
+
content: '';
|
|
700
|
+
position: absolute;
|
|
701
|
+
top: 0;
|
|
702
|
+
left: 0px;
|
|
703
|
+
height: 100%;
|
|
704
|
+
width: 2px;
|
|
705
|
+
background: #262626;
|
|
706
|
+
}
|
|
707
|
+
.dt-row.dt-selected .dt-lbl .dt-tag{
|
|
708
|
+
background: var(--bg-primary-default, #262626)!important;
|
|
709
|
+
color: var(--text-primary-default, #FFF)!important;
|
|
710
|
+
}
|
|
597
711
|
.dt-chev{
|
|
598
712
|
width:16px;height:16px;flex-shrink:0;border:none;background:transparent;
|
|
599
713
|
cursor:pointer;color:var(--text-3);display:flex;align-items:center;justify-content:center;
|
|
@@ -602,22 +716,36 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
602
716
|
.dt-chev:hover{color:var(--text)}
|
|
603
717
|
.dt-chev.dt-spacer{visibility:hidden;pointer-events:none}
|
|
604
718
|
.dt-ico{width:16px;flex-shrink:0;text-align:center;color:var(--text-3);font-size:12px}
|
|
605
|
-
.dt-lbl{
|
|
719
|
+
.dt-lbl{
|
|
720
|
+
flex: 1;
|
|
721
|
+
overflow: hidden;
|
|
722
|
+
text-overflow: ellipsis;
|
|
723
|
+
white-space: nowrap;
|
|
724
|
+
color: var(--content-strong, #171717);
|
|
725
|
+
font-family: "JetBrains Mono";
|
|
726
|
+
}
|
|
606
727
|
.dt-muted{padding:16px 12px;text-align:center;color:var(--text-3);font-size:11px;line-height:1.4}
|
|
607
728
|
#section-components-panel{
|
|
608
729
|
max-height: 50%;
|
|
609
730
|
overflow-y: auto;
|
|
731
|
+
flex-shrink: 0;
|
|
732
|
+
display: flex;
|
|
733
|
+
flex-direction: column;
|
|
610
734
|
}
|
|
735
|
+
#section-components-panel .lp-body.collapsed{display:none}
|
|
611
736
|
/* \u2500\u2500 Right panel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
612
737
|
#right-panel{
|
|
613
|
-
width:
|
|
738
|
+
width:288px;
|
|
739
|
+
border-left: 1px solid var(--border-default, #E5E5E5);
|
|
740
|
+
background: var(--cu-Background-Main, #FFF);
|
|
614
741
|
display:flex;flex-direction:column;flex-shrink:0;overflow:hidden
|
|
615
742
|
}
|
|
616
743
|
|
|
617
744
|
/* \u2500\u2500 Breadcrumb \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
618
745
|
#breadcrumb{
|
|
746
|
+
display:none;
|
|
619
747
|
height:26px;background:var(--bg);border-top:1px solid var(--border);
|
|
620
|
-
|
|
748
|
+
align-items:center;padding:0 12px;font-size:11px;
|
|
621
749
|
color:var(--text-3);flex-shrink:0;gap:5px;overflow:hidden
|
|
622
750
|
}
|
|
623
751
|
|
|
@@ -630,9 +758,13 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
630
758
|
|
|
631
759
|
/* \u2500\u2500 Device frame \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
632
760
|
#device-frame{
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
761
|
+
width: 100%;
|
|
762
|
+
min-height: 100%;
|
|
763
|
+
display: flex;
|
|
764
|
+
align-items: center;
|
|
765
|
+
transform-origin: top left;
|
|
766
|
+
transition: max-width .3s ease,width .2s ease,height .2s ease;
|
|
767
|
+
flex-shrink: 0;
|
|
636
768
|
}
|
|
637
769
|
#device-frame.desktop{
|
|
638
770
|
max-width:1440px;
|
|
@@ -683,33 +815,51 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
683
815
|
}
|
|
684
816
|
|
|
685
817
|
/* \u2500\u2500 Left panel sections \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
686
|
-
.lp-sec{border-bottom:1px solid var(--border);flex-shrink:0;padding: 24px;}
|
|
818
|
+
.lp-sec{border-bottom:1px solid var(--border);flex-shrink:0;padding: 24px 16px;}
|
|
687
819
|
.lp-sec-no-border{border-bottom:none!important}
|
|
688
820
|
.lp-sec-hd{
|
|
689
821
|
margin-bottom: 12px;
|
|
690
822
|
font-size:14px;font-weight:600;
|
|
823
|
+
line-height: 20px;
|
|
691
824
|
color:#404040;display:flex;align-items:center;justify-content:space-between;gap:5px
|
|
692
825
|
}
|
|
693
826
|
.lp-sec-hd-left{display:flex;align-items:center;gap:5px}
|
|
694
827
|
#active-var-label{display:none;color:var(--accent-txt);font-size:10px;font-weight:500}
|
|
695
828
|
.lp-info-icon{font-size:11px;color:var(--text-3);cursor:default;opacity:.7}
|
|
696
829
|
.lp-add-btn{
|
|
697
|
-
|
|
698
|
-
|
|
830
|
+
background: none;
|
|
831
|
+
border: none;
|
|
832
|
+
cursor: pointer;
|
|
833
|
+
padding: 2px 5px;
|
|
834
|
+
border-radius: 4px;
|
|
835
|
+
transition: all .12s;
|
|
836
|
+
flex-shrink: 0;
|
|
837
|
+
color: var(--content-default, #404040);
|
|
838
|
+
text-align: center;
|
|
839
|
+
font-family: Inter;
|
|
840
|
+
font-size: 12px;
|
|
841
|
+
font-style: normal;
|
|
842
|
+
font-weight: 500;
|
|
843
|
+
line-height: 14px;
|
|
699
844
|
}
|
|
700
|
-
.lp-add-btn:hover{
|
|
845
|
+
.lp-add-btn:hover{opacity:0.8}
|
|
701
846
|
|
|
702
847
|
/* \u2500\u2500 Variation tabs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
703
848
|
#variation-tabs{display:flex;flex-direction:column; gap:8px;}
|
|
704
849
|
.var-tab{
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
850
|
+
border-radius: var(--radius-md, 6px);
|
|
851
|
+
border:1px solid transparent;
|
|
852
|
+
background: var(--bg-interactive-default, #FFF);
|
|
853
|
+
box-shadow: 0 0 1px 0 var(--Black-20, rgba(0, 0, 0, 0.20)), 0 1px 2px 0 var(--Black-5, rgba(0, 0, 0, 0.05)), 0 1px 1px 0 rgba(0, 0, 0, 0.01);
|
|
854
|
+
cursor:pointer;font-size:15px;font-weight:500;padding:7px 10px;transition:background .12s,color .12s,border-color .12s;
|
|
709
855
|
width:100%;text-align:left;display:flex;align-items:center;gap:8px;
|
|
856
|
+
line-height: 16px;
|
|
710
857
|
}
|
|
711
858
|
.var-tab:hover{background:var(--bg-hover);color:var(--text)}
|
|
712
|
-
.var-tab.active{
|
|
859
|
+
button.var-tab.active{
|
|
860
|
+
color:var(--accent-txt);
|
|
861
|
+
border-color:var(--var-tab-color, transparent);
|
|
862
|
+
}
|
|
713
863
|
.var-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}
|
|
714
864
|
.var-add-row{
|
|
715
865
|
display:none!important;
|
|
@@ -723,51 +873,207 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
723
873
|
.var-add-row:hover{color:var(--accent-txt)}
|
|
724
874
|
|
|
725
875
|
/* \u2500\u2500 Search \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
876
|
+
.lp-search-container{margin-bottom:8px}
|
|
877
|
+
.lp-search-field{
|
|
878
|
+
position:relative;
|
|
879
|
+
display:flex;
|
|
880
|
+
align-items:center;
|
|
881
|
+
width:100%;
|
|
882
|
+
}
|
|
883
|
+
.lp-search-icon{
|
|
884
|
+
position:absolute;
|
|
885
|
+
left:12px;
|
|
886
|
+
top:50%;
|
|
887
|
+
transform:translateY(-50%);
|
|
888
|
+
display:flex;
|
|
889
|
+
align-items:center;
|
|
890
|
+
justify-content:center;
|
|
891
|
+
width:16px;
|
|
892
|
+
height:16px;
|
|
893
|
+
pointer-events:none;
|
|
894
|
+
color:var(--base-sub-2,#B5B5B5);
|
|
895
|
+
flex-shrink:0;
|
|
896
|
+
}
|
|
897
|
+
.lp-search-icon svg{display:block;width:16px;height:16px}
|
|
898
|
+
.lp-search-icon svg path{stroke:currentColor}
|
|
726
899
|
#comp-search{
|
|
727
|
-
|
|
728
|
-
color:var(--text);
|
|
900
|
+
border:1px solid var(--border);
|
|
901
|
+
color:var(--text);
|
|
902
|
+
font-size:12px;
|
|
903
|
+
padding:9px 12px 9px 36px;
|
|
904
|
+
width:100%;
|
|
905
|
+
outline:none;
|
|
906
|
+
border-radius:6px;
|
|
907
|
+
background:var(--Greyscale-0,#FFF);
|
|
908
|
+
box-shadow:0 0 1px 0 var(--Black-20,rgba(0,0,0,.20)),0 1px 2px 0 var(--Black-5,rgba(0,0,0,.05)),0 1px 1px 0 rgba(0,0,0,.01);
|
|
729
909
|
}
|
|
730
|
-
#comp-search::placeholder{
|
|
731
|
-
|
|
732
|
-
|
|
910
|
+
#comp-search::placeholder{
|
|
911
|
+
color:var(--base-sub-2,#B5B5B5);
|
|
912
|
+
font-size:var(--font-size-sm,14px);
|
|
913
|
+
font-style:normal;
|
|
914
|
+
font-weight:500;
|
|
915
|
+
}
|
|
916
|
+
#comp-search:focus{border-color:#000;}
|
|
733
917
|
/* \u2500\u2500 Left tabs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
734
|
-
.lp-tabs
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
918
|
+
.lp-tabs-container{
|
|
919
|
+
display:flex;
|
|
920
|
+
align-items:center;
|
|
921
|
+
justify-content:space-between;
|
|
738
922
|
}
|
|
739
|
-
.lp-
|
|
740
|
-
|
|
741
|
-
|
|
923
|
+
.lp-tabs{
|
|
924
|
+
width: 100%;
|
|
925
|
+
padding: 4px 10px;
|
|
926
|
+
flex: 1;
|
|
742
927
|
display: flex;
|
|
743
|
-
|
|
928
|
+
border-radius: 6px;
|
|
929
|
+
background: var(--base-soft-2,#F0F0F0);
|
|
930
|
+
padding: 4px 6px;
|
|
931
|
+
flex-shrink: 0;
|
|
932
|
+
gap: 6px;
|
|
933
|
+
align-items: center;
|
|
934
|
+
white-space: nowrap;
|
|
935
|
+
}
|
|
936
|
+
.lp-tab{
|
|
937
|
+
flex: 1;
|
|
938
|
+
text-align: center;
|
|
939
|
+
color: #404040;
|
|
940
|
+
white-space: nowrap;
|
|
941
|
+
cursor: pointer;
|
|
942
|
+
transition: all .15s;
|
|
943
|
+
line-height: 1.15;
|
|
944
|
+
font-size: var(--font-size-sm,14px);
|
|
945
|
+
font-weight: 500;
|
|
946
|
+
padding:4px 10px;
|
|
947
|
+
}
|
|
948
|
+
.section-components-tabs-container{
|
|
949
|
+
display: flex;
|
|
744
950
|
align-items: center;
|
|
745
|
-
justify-content:
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
951
|
+
justify-content: space-between;
|
|
952
|
+
flex-shrink: 0;
|
|
953
|
+
padding: 12px 16px;
|
|
954
|
+
border-bottom: 1px solid #F5F5F5;
|
|
955
|
+
}
|
|
956
|
+
.section-components-tabs-container .lp-tabs{
|
|
957
|
+
flex:1;
|
|
749
958
|
}
|
|
959
|
+
.lp-tab.close-section-components-panel{
|
|
960
|
+
flex:0 0 auto;
|
|
961
|
+
flex-shrink:0;
|
|
962
|
+
display:flex;
|
|
963
|
+
align-items:center;
|
|
964
|
+
justify-content:center;
|
|
965
|
+
width:24px;
|
|
966
|
+
height:24px;
|
|
967
|
+
padding:0;
|
|
968
|
+
background:none;
|
|
969
|
+
border-radius:4px;
|
|
970
|
+
color:var(--content-default,#404040);
|
|
971
|
+
line-height:1;
|
|
972
|
+
white-space:nowrap;
|
|
973
|
+
}
|
|
974
|
+
.lp-tab.close-section-components-panel i{
|
|
975
|
+
font-size:14px;
|
|
976
|
+
line-height:1;
|
|
977
|
+
transition:transform .15s;
|
|
978
|
+
}
|
|
979
|
+
.lp-tab.close-section-components-panel.collapsed i{transform:rotate(-180deg)}
|
|
750
980
|
.lp-tab:hover{color:var(--text-2)}
|
|
751
|
-
.lp-tab.active{
|
|
981
|
+
.lp-tab.active{
|
|
982
|
+
border-radius:4px;
|
|
983
|
+
background:var(--bg-interactive-default,#FFF);
|
|
984
|
+
box-shadow:0 0 1px 0 var(--Black-20,rgba(0,0,0,.20)),0 1px 2px 0 var(--Black-5,rgba(0,0,0,.05)),0 1px 1px 0 rgba(0,0,0,.01);
|
|
985
|
+
}
|
|
986
|
+
.lp-tab.close-section-components-panel:hover{opacity:.8;color:var(--text-2)}
|
|
987
|
+
.lp-tab.close-section-components-panel.active{
|
|
988
|
+
background:none;
|
|
989
|
+
box-shadow:none;
|
|
990
|
+
border-radius:4px;
|
|
991
|
+
}
|
|
752
992
|
.future-hidden{display:none!important}
|
|
753
993
|
|
|
754
994
|
/* \u2500\u2500 Left panel body \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
995
|
+
.lp-body #tab-dom-tree, .lp-body #tab-elements{
|
|
996
|
+
padding-top:4px;
|
|
997
|
+
}
|
|
998
|
+
.lp-body #tab-elements .dt-lbl{
|
|
999
|
+
font-size: 12px;
|
|
1000
|
+
font-style: normal;
|
|
1001
|
+
font-weight: 500;
|
|
1002
|
+
line-height: 14px;
|
|
1003
|
+
letter-spacing: -0.1px;
|
|
1004
|
+
}
|
|
1005
|
+
.lp-body #tab-elements #elements-root > .dt-row{
|
|
1006
|
+
padding-left: 16px!important;
|
|
1007
|
+
}
|
|
1008
|
+
.lp-body #dom-tree-root .dt-lbl{
|
|
1009
|
+
color: var(--content-subtle, #737373);
|
|
1010
|
+
font-style: normal;
|
|
1011
|
+
font-weight: 400;
|
|
1012
|
+
line-height: var(--font-leading-3, 12px); /* 100% */
|
|
1013
|
+
letter-spacing: -0.1px;
|
|
1014
|
+
}
|
|
1015
|
+
.lp-body #dom-tree-root .dt-lbl .dt-tag{
|
|
1016
|
+
color: var(--content-strong, #171717);
|
|
1017
|
+
font-family: "JetBrains Mono";
|
|
1018
|
+
font-size: 12px;
|
|
1019
|
+
font-style: normal;
|
|
1020
|
+
font-weight: 500;
|
|
1021
|
+
line-height: 14px;
|
|
1022
|
+
letter-spacing: -0.1px;
|
|
1023
|
+
border-radius: 4px;
|
|
1024
|
+
background: var(--bg-surface-subtle, #F5F5F5);
|
|
1025
|
+
padding:3px 6px;
|
|
1026
|
+
display:inline-block;
|
|
1027
|
+
margin-right:4px;
|
|
1028
|
+
}
|
|
1029
|
+
.lp-body #tab-elements .dt-row .dt-chev.dt-spacer{display:none;}
|
|
1030
|
+
.lp-body #tab-dom-tree .dt-row .dt-ico{display:none;}
|
|
755
1031
|
.lp-body, .section-components-body{flex:1;overflow-y:auto}
|
|
756
1032
|
.lp-body::-webkit-scrollbar, .section-components-body::-webkit-scrollbar{width:3px}
|
|
757
1033
|
.lp-body::-webkit-scrollbar-thumb, .section-components-body::-webkit-scrollbar-thumb{background:#cbd5e1;border-radius:2px}
|
|
758
1034
|
.tab-pane, .section-components-tab-pane{display:none}.tab-pane.active, .section-components-tab-pane.active{display:block}
|
|
759
1035
|
|
|
760
1036
|
/* \u2500\u2500 Component grid \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
761
|
-
.cg-hdr{padding:
|
|
762
|
-
|
|
1037
|
+
.cg-hdr{ padding: 12px 12px;
|
|
1038
|
+
text-transform: uppercase;
|
|
1039
|
+
letter-spacing: .06em;
|
|
1040
|
+
color: var(--content-subtle, #737373);
|
|
1041
|
+
font-family: Inter;
|
|
1042
|
+
font-size: 12px;
|
|
1043
|
+
font-weight: 600;
|
|
1044
|
+
line-height: normal;
|
|
1045
|
+
}
|
|
1046
|
+
.cg-grid{ display: grid;
|
|
1047
|
+
grid-template-columns: 1fr 1fr 1fr;
|
|
1048
|
+
padding: 0 12px 12px;
|
|
1049
|
+
column-gap: 8px;
|
|
1050
|
+
row-gap: 12px;}
|
|
763
1051
|
.cg-item{
|
|
764
|
-
|
|
765
|
-
|
|
1052
|
+
background: #fff;
|
|
1053
|
+
cursor: pointer;
|
|
1054
|
+
padding: 15px 11px;
|
|
1055
|
+
text-align: center;
|
|
1056
|
+
transition: all .15s;
|
|
1057
|
+
color: var(--text-2);
|
|
1058
|
+
user-select: none;
|
|
1059
|
+
border-radius: 6px;
|
|
1060
|
+
border: 1px solid var(--border-default, #E5E5E5);
|
|
766
1061
|
}
|
|
767
1062
|
.cg-item:hover{background:var(--accent-bg);border-color:var(--accent);color:var(--accent-txt);transform:translateY(-1px);box-shadow:0 2px 8px rgba(99,102,241,.15)}
|
|
768
1063
|
.cg-item:active{transform:translateY(0);box-shadow:none}
|
|
769
|
-
.cg-icon{
|
|
770
|
-
|
|
1064
|
+
.cg-icon{ margin-bottom: 6px;
|
|
1065
|
+
color: var(--content-default, #404040);
|
|
1066
|
+
font-family: Inter;
|
|
1067
|
+
font-size: var(--font-size-sm, 14px);
|
|
1068
|
+
font-style: normal;
|
|
1069
|
+
font-weight: 500;
|
|
1070
|
+
line-height: var(--font-leading-4, 16px);}
|
|
1071
|
+
.cg-name{ color: var(--content-subtle, #737373);
|
|
1072
|
+
font-family: Inter;
|
|
1073
|
+
font-size: var(--font-size-xs, 12px);
|
|
1074
|
+
font-style: normal;
|
|
1075
|
+
font-weight: 400;
|
|
1076
|
+
line-height: var(--font-leading-3, 12px);}
|
|
771
1077
|
|
|
772
1078
|
/* \u2500\u2500 Section list \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
773
1079
|
.sec-item{
|
|
@@ -776,8 +1082,12 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
776
1082
|
}
|
|
777
1083
|
.sec-item:hover{border-color:var(--accent);transform:translateY(-1px);box-shadow:0 4px 12px rgba(99,102,241,.12)}
|
|
778
1084
|
.sec-thumb{
|
|
779
|
-
background:var(--bg-sub);height:
|
|
780
|
-
justify-content:center;font-size:22px;border-bottom:1px solid var(--border)
|
|
1085
|
+
background:var(--bg-sub);height:auto;display:flex;align-items:center;
|
|
1086
|
+
justify-content:center;font-size:22px;border-bottom:1px solid var(--border);
|
|
1087
|
+
overflow:hidden;
|
|
1088
|
+
}
|
|
1089
|
+
.sec-thumb img{
|
|
1090
|
+
width:100%;height:100%;object-fit:cover;object-position:top center;display:block;
|
|
781
1091
|
}
|
|
782
1092
|
.sec-info{padding:7px 9px}
|
|
783
1093
|
.sec-name{font-size:11px;font-weight:600;color:var(--text)}
|
|
@@ -793,11 +1103,26 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
793
1103
|
#no-sel .ns-icon{font-size:32px;margin-bottom:10px;opacity:.4}
|
|
794
1104
|
|
|
795
1105
|
/* \u2500\u2500 Element info header \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
796
|
-
#el-info{padding:8px 12px;border-bottom:1px solid var(--border);background:var(--bg-sub);flex-shrink:0}
|
|
797
|
-
#el-info-tag{font-size:10px;font-weight:700;color:var(--text-3);text-transform:uppercase;letter-spacing:.05em;font-family:
|
|
798
|
-
#el-info-sel{font-size:10px;color:var(--accent-txt);font-family:
|
|
1106
|
+
#el-info{padding:8px 12px;border-bottom:1px solid var(--border);background:var(--bg-sub);flex-shrink:0;display:none;}
|
|
1107
|
+
#el-info-tag{font-size:10px;font-weight:700;color:var(--text-3);text-transform:uppercase;letter-spacing:.05em;font-family:var(--font-mono)}
|
|
1108
|
+
#el-info-sel{font-size:10px;color:var(--accent-txt);font-family:var(--font-mono);margin-top:2px;word-break:break-all;opacity:.8}
|
|
799
1109
|
|
|
800
1110
|
/* \u2500\u2500 Accordion \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
1111
|
+
#tab-design.rp-pane.active{
|
|
1112
|
+
display:flex;
|
|
1113
|
+
flex-direction:column;
|
|
1114
|
+
min-height:0;
|
|
1115
|
+
overflow-y:auto;
|
|
1116
|
+
overflow-x:hidden;
|
|
1117
|
+
}
|
|
1118
|
+
#rp-accordion.rp-accordion{
|
|
1119
|
+
flex:1;
|
|
1120
|
+
min-height:0;
|
|
1121
|
+
overflow-y:auto;
|
|
1122
|
+
overflow-x:hidden;
|
|
1123
|
+
}
|
|
1124
|
+
#rp-accordion.rp-accordion::-webkit-scrollbar{width:3px}
|
|
1125
|
+
#rp-accordion.rp-accordion::-webkit-scrollbar-thumb{background:#e2e8f0;border-radius:2px}
|
|
801
1126
|
.acc-section{border-bottom:1px solid var(--border-sub)}
|
|
802
1127
|
.acc-hd{
|
|
803
1128
|
display:flex;align-items:center;padding:11px 14px;cursor:pointer;
|
|
@@ -850,7 +1175,7 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
850
1175
|
.custom-css-close:hover{background:var(--bg-hover);color:var(--text)}
|
|
851
1176
|
#custom-css-modal-textarea{
|
|
852
1177
|
width:100%;min-height:360px;max-height:58vh;resize:vertical;border:none;outline:none;
|
|
853
|
-
font-family:
|
|
1178
|
+
font-family:var(--font-mono);
|
|
854
1179
|
font-size:12px;line-height:1.5;padding:12px;background:#0b1220;color:#e2e8f0
|
|
855
1180
|
}
|
|
856
1181
|
.custom-css-actions{
|
|
@@ -893,7 +1218,7 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
893
1218
|
.adv-section{padding:10px}
|
|
894
1219
|
.adv-row{margin-bottom:8px}
|
|
895
1220
|
.adv-key{font-size:10px;color:var(--text-3);margin-bottom:3px;font-weight:700;text-transform:uppercase;letter-spacing:.05em}
|
|
896
|
-
.adv-val{font-size:11px;color:var(--text-2);word-break:break-all;background:var(--bg-sub);padding:5px 7px;border-radius:5px;font-family:
|
|
1221
|
+
.adv-val{font-size:11px;color:var(--text-2);word-break:break-all;background:var(--bg-sub);padding:5px 7px;border-radius:5px;font-family:var(--font-mono);border:1px solid var(--border)}
|
|
897
1222
|
|
|
898
1223
|
/* \u2500\u2500 Selected element ring + drag affordance \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
899
1224
|
/* Selection chrome is injected into the iframe (see injectIframeSelectionStyles); rules here are fallback only */
|
|
@@ -926,15 +1251,48 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
926
1251
|
}
|
|
927
1252
|
.img-add:hover{border-color:var(--accent);color:var(--accent-txt);background:var(--accent-bg)}
|
|
928
1253
|
|
|
1254
|
+
/* \u2500\u2500 Video properties 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 */
|
|
1255
|
+
.video-preview{
|
|
1256
|
+
width:100%;height:120px;object-fit:contain;border:1px solid var(--border);
|
|
1257
|
+
border-radius:6px;background:#000;margin-bottom:8px;display:block
|
|
1258
|
+
}
|
|
1259
|
+
.embed-preview{
|
|
1260
|
+
width:100%;aspect-ratio:16/9;border:1px solid var(--border);
|
|
1261
|
+
border-radius:6px;background:#000;margin-bottom:8px;display:block;border:none
|
|
1262
|
+
}
|
|
1263
|
+
|
|
929
1264
|
/* \u2500\u2500 Right panel main tabs (Design / States / History) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
930
|
-
#main-tabs{
|
|
1265
|
+
#main-tabs{
|
|
1266
|
+
display:flex;
|
|
1267
|
+
align-items:center;
|
|
1268
|
+
gap:6px;
|
|
1269
|
+
margin:12px 16px 8px;
|
|
1270
|
+
padding:4px 6px;
|
|
1271
|
+
border-radius:6px;
|
|
1272
|
+
background:var(--base-soft-2,#F0F0F0);
|
|
1273
|
+
flex-shrink:0;
|
|
1274
|
+
}
|
|
931
1275
|
.main-tab{
|
|
932
|
-
flex:1;
|
|
933
|
-
|
|
934
|
-
|
|
1276
|
+
flex:1;
|
|
1277
|
+
padding:4px 10px;
|
|
1278
|
+
text-align:center;
|
|
1279
|
+
font-size:var(--font-size-sm,14px);
|
|
1280
|
+
font-weight:500;
|
|
1281
|
+
line-height:1.15;
|
|
1282
|
+
color:#404040;
|
|
1283
|
+
white-space:nowrap;
|
|
1284
|
+
cursor:pointer;
|
|
1285
|
+
border:none;
|
|
1286
|
+
background:transparent;
|
|
1287
|
+
transition:all .15s;
|
|
1288
|
+
font-family:inherit;
|
|
935
1289
|
}
|
|
936
1290
|
.main-tab:hover{color:var(--text-2)}
|
|
937
|
-
.main-tab.active{
|
|
1291
|
+
.main-tab.active{
|
|
1292
|
+
border-radius:4px;
|
|
1293
|
+
background:var(--bg-interactive-default,#FFF);
|
|
1294
|
+
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);
|
|
1295
|
+
}
|
|
938
1296
|
.rp-pane{flex:1;overflow-y:auto;overflow-x:hidden;min-width:0;display:none}
|
|
939
1297
|
.rp-pane.active{display:block}
|
|
940
1298
|
|
|
@@ -943,13 +1301,13 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
943
1301
|
.states-empty i{font-size:30px;display:block;margin-bottom:10px;opacity:.3}
|
|
944
1302
|
.state-group{border-bottom:1px solid var(--border-sub)}
|
|
945
1303
|
.state-group-sel{
|
|
946
|
-
padding:8px 12px 3px;font-size:10px;font-family:
|
|
1304
|
+
padding:8px 12px 3px;font-size:10px;font-family:var(--font-mono);
|
|
947
1305
|
color:var(--text-3);font-weight:700;word-break:break-all;letter-spacing:-.01em
|
|
948
1306
|
}
|
|
949
1307
|
.state-item{display:flex;align-items:center;padding:4px 10px 4px 18px;gap:6px}
|
|
950
1308
|
.state-item-label{flex:1;font-size:11px;color:var(--text-2)}
|
|
951
1309
|
.state-item-val{
|
|
952
|
-
font-size:10px;color:var(--accent-txt);font-family:
|
|
1310
|
+
font-size:10px;color:var(--accent-txt);font-family:var(--font-mono);
|
|
953
1311
|
max-width:68px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
|
|
954
1312
|
background:var(--accent-bg);padding:1px 5px;border-radius:3px
|
|
955
1313
|
}
|
|
@@ -1044,9 +1402,56 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1044
1402
|
.history-remove{
|
|
1045
1403
|
margin-top:2px;
|
|
1046
1404
|
}
|
|
1405
|
+
|
|
1406
|
+
/* \u2500\u2500 Minimum screen size gate \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
1407
|
+
#ve-min-screen-notice{
|
|
1408
|
+
display:none;
|
|
1409
|
+
position:fixed;
|
|
1410
|
+
inset:0;
|
|
1411
|
+
z-index:99999;
|
|
1412
|
+
flex-direction:column;
|
|
1413
|
+
align-items:center;
|
|
1414
|
+
justify-content:center;
|
|
1415
|
+
gap:12px;
|
|
1416
|
+
padding:24px;
|
|
1417
|
+
text-align:center;
|
|
1418
|
+
background:#f1f5f9;
|
|
1419
|
+
color:#404040;
|
|
1420
|
+
}
|
|
1421
|
+
#ve-min-screen-notice .ve-min-screen-icon{
|
|
1422
|
+
font-size:40px;
|
|
1423
|
+
color:#737373;
|
|
1424
|
+
line-height:1;
|
|
1425
|
+
}
|
|
1426
|
+
#ve-min-screen-notice .ve-min-screen-title{
|
|
1427
|
+
font-size:18px;
|
|
1428
|
+
font-weight:600;
|
|
1429
|
+
color:#262626;
|
|
1430
|
+
max-width:420px;
|
|
1431
|
+
}
|
|
1432
|
+
#ve-min-screen-notice .ve-min-screen-desc{
|
|
1433
|
+
font-size:14px;
|
|
1434
|
+
color:#737373;
|
|
1435
|
+
max-width:420px;
|
|
1436
|
+
line-height:1.5;
|
|
1437
|
+
}
|
|
1438
|
+
@media (max-width:1100px){
|
|
1439
|
+
#app,
|
|
1440
|
+
#custom-css-modal{
|
|
1441
|
+
display:none!important;
|
|
1442
|
+
}
|
|
1443
|
+
#ve-min-screen-notice{
|
|
1444
|
+
display:flex;
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1047
1447
|
</style>
|
|
1048
1448
|
</head>
|
|
1049
1449
|
<body class="mode-editor">
|
|
1450
|
+
<div id="ve-min-screen-notice" aria-live="polite">
|
|
1451
|
+
<div class="ve-min-screen-icon"><i class="bi bi-display"></i></div>
|
|
1452
|
+
<div class="ve-min-screen-title">Please switch to greater or bigger screen to use Visual Editor</div>
|
|
1453
|
+
<div class="ve-min-screen-desc">The Visual Editor requires a screen width of at least 1100px.</div>
|
|
1454
|
+
</div>
|
|
1050
1455
|
<div id="app">
|
|
1051
1456
|
<!-- \u2500\u2500 Toolbar \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->
|
|
1052
1457
|
<div id="toolbar">
|
|
@@ -1077,7 +1482,17 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1077
1482
|
<div id="dev-more-menu" class="tb-dev-menu" aria-hidden="true">
|
|
1078
1483
|
<div class="row row-zoom">
|
|
1079
1484
|
<label for="dev-zoom-level">Zoom</label>
|
|
1080
|
-
<
|
|
1485
|
+
<div class="zoom-controls">
|
|
1486
|
+
<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">
|
|
1487
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true">
|
|
1488
|
+
<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"/>
|
|
1489
|
+
<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"/>
|
|
1490
|
+
<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"/>
|
|
1491
|
+
<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"/>
|
|
1492
|
+
</svg>
|
|
1493
|
+
</button>
|
|
1494
|
+
<input id="dev-zoom-level" type="number" min="25" max="200" step="5" value="100" />
|
|
1495
|
+
</div>
|
|
1081
1496
|
</div>
|
|
1082
1497
|
<div class="row row-split row-width height-width-row">
|
|
1083
1498
|
<div class="row" style="margin:0">
|
|
@@ -1102,9 +1517,6 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1102
1517
|
<button type="button" class="vp-preset-btn" data-preset="iphone-7">iPhone 7</button>
|
|
1103
1518
|
<button type="button" class="vp-preset-btn" data-preset="responsive">Responsive</button>
|
|
1104
1519
|
</div>
|
|
1105
|
-
<div class="ft">
|
|
1106
|
-
<button type="button" class="apply-btn" id="dev-apply-btn">Apply</button>
|
|
1107
|
-
</div>
|
|
1108
1520
|
</div>
|
|
1109
1521
|
</div>
|
|
1110
1522
|
<button class="tb-dk-btn" id="btn-undo" title="Undo (\u2318Z)"><i class="bi bi-arrow-counterclockwise"></i></button>
|
|
@@ -1132,15 +1544,16 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1132
1544
|
<span class="tb-save-txt"></span>
|
|
1133
1545
|
<span id="tb-save-time" class="tb-save-time"></span>
|
|
1134
1546
|
</div>
|
|
1547
|
+
<button class="tb-fin-btn" id="btn-save">Save Changes</button>
|
|
1135
1548
|
<div class="tb-dev-3btns">
|
|
1136
1549
|
<button class="tb-dk-btn active" id="btn-mode-editor" onclick="setMode('editor')" title="Edit mode \u2014 click elements to edit"><i class="bi bi-pencil"></i></button>
|
|
1137
|
-
<button class="tb-dk-btn" id="btn-mode-nav" onclick="setMode('navigate')" title="Navigate mode \u2014 interact with page normally"><i class="bi bi-
|
|
1550
|
+
<button class="tb-dk-btn" id="btn-mode-nav" onclick="setMode('navigate')" title="Navigate mode \u2014 interact with page normally"><i class="bi bi-cursor"></i></button>
|
|
1138
1551
|
<button class="tb-dk-btn" title="Comments"><i class="bi bi-chat-dots"></i></button>
|
|
1139
1552
|
</div>
|
|
1140
|
-
<button class="tb-sim-btn" id="btn-simulate" onclick="simulateExperiment()"
|
|
1141
|
-
|
|
1553
|
+
<button class="tb-sim-btn" id="btn-simulate" onclick="simulateExperiment()">See Preview</button>
|
|
1554
|
+
|
|
1142
1555
|
<!-- btn-close: kept for JS event listener -->
|
|
1143
|
-
<button class="tb-fin-btn" id="btn-close">
|
|
1556
|
+
<button class="tb-fin-btn" id="btn-close">Exit Editor</button>
|
|
1144
1557
|
</div>
|
|
1145
1558
|
|
|
1146
1559
|
<!-- url-bar: hidden, kept for JS compatibility -->
|
|
@@ -1178,22 +1591,28 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1178
1591
|
|
|
1179
1592
|
<!-- Elements -->
|
|
1180
1593
|
<div class="lp-sec lp-sec-no-border">
|
|
1181
|
-
<div class="lp-sec-hd">
|
|
1182
|
-
<span class="lp-sec-hd-left">Elements <i style="display:none" class="bi bi-info-circle lp-info-icon" title="Page elements"></i></span>
|
|
1183
|
-
<button class="lp-add-btn" id="btn-add-element" title="Add element">+ Add</button>
|
|
1184
|
-
</div>
|
|
1185
|
-
|
|
1186
1594
|
<!-- Search (hidden, kept for JS) -->
|
|
1187
|
-
<div>
|
|
1188
|
-
<
|
|
1595
|
+
<div class="lp-search-container">
|
|
1596
|
+
<div class="lp-search-field">
|
|
1597
|
+
<span class="lp-search-icon" aria-hidden="true">
|
|
1598
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
|
|
1599
|
+
<path d="M11.333 11.3333L13.9997 13.9999" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
|
1600
|
+
<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"/>
|
|
1601
|
+
</svg>
|
|
1602
|
+
</span>
|
|
1603
|
+
<input type="search" id="comp-search" placeholder="Search" autocomplete="off">
|
|
1604
|
+
</div>
|
|
1189
1605
|
</div>
|
|
1190
1606
|
|
|
1191
1607
|
|
|
1192
1608
|
<!-- Tabs (hidden, kept for JS) -->
|
|
1193
|
-
<div class="lp-tabs"
|
|
1194
|
-
<div class="lp-
|
|
1609
|
+
<div class="lp-tabs-container">
|
|
1610
|
+
<div class="lp-tabs">
|
|
1611
|
+
<div class="lp-tab active" onclick="switchLeftTab('elements')">Elements</div>
|
|
1195
1612
|
<div class="lp-tab" onclick="switchLeftTab('dom-tree')">DOM Tree</div>
|
|
1196
1613
|
</div>
|
|
1614
|
+
<button class="lp-add-btn" id="btn-add-element" title="Add element">+ Add</button>
|
|
1615
|
+
</div>
|
|
1197
1616
|
|
|
1198
1617
|
</div>
|
|
1199
1618
|
|
|
@@ -1222,11 +1641,11 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1222
1641
|
|
|
1223
1642
|
<!-- Floating toolbar for selected element (positioned over iframe) -->
|
|
1224
1643
|
<div id="selection-floater" aria-label="Selection actions">
|
|
1644
|
+
<button type="button" class="sf-btn" id="sf-add" title="Add element"><i class="bi bi-plus-lg"></i></button>
|
|
1645
|
+
<span class="sf-sep"></span>
|
|
1225
1646
|
<button type="button" class="sf-btn" id="sf-move-up" title="Move up"><i class="bi bi-arrow-up"></i></button>
|
|
1226
1647
|
<button type="button" class="sf-btn" id="sf-move-down" title="Move down"><i class="bi bi-arrow-down"></i></button>
|
|
1227
1648
|
<span class="sf-sep"></span>
|
|
1228
|
-
<button type="button" class="sf-btn" id="sf-resize" disabled title="Resize (coming soon)"><i class="bi bi-arrows-angle-expand"></i></button>
|
|
1229
|
-
<button type="button" class="sf-btn" id="sf-rotate" disabled title="Rotate (coming soon)"><i class="bi bi-arrow-repeat"></i></button>
|
|
1230
1649
|
<button type="button" class="sf-btn" id="sf-dup" title="Duplicate"><i class="bi bi-files"></i></button>
|
|
1231
1650
|
<button type="button" class="sf-btn" id="sf-hide" title="Hide"><i class="bi bi-eye-slash"></i></button>
|
|
1232
1651
|
<button type="button" class="sf-btn" id="sf-del" title="Delete"><i class="bi bi-trash"></i></button>
|
|
@@ -1250,15 +1669,17 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1250
1669
|
|
|
1251
1670
|
<!-- Right panel -->
|
|
1252
1671
|
<div id="right-panel">
|
|
1253
|
-
<div id="section-components-panel"
|
|
1672
|
+
<div id="section-components-panel">
|
|
1254
1673
|
<!-- Left-tab controls moved here -->
|
|
1255
|
-
<div class="section-components-tabs">
|
|
1256
|
-
<div class="lp-
|
|
1257
|
-
|
|
1258
|
-
|
|
1674
|
+
<div class="lp-tabs-container section-components-tabs-container">
|
|
1675
|
+
<div class="lp-tabs">
|
|
1676
|
+
<div class="lp-tab active" onclick="switchSectionComponentsTab('components')">Components</div>
|
|
1677
|
+
<div class="lp-tab" onclick="switchSectionComponentsTab('sections')">Sections</div>
|
|
1678
|
+
</div>
|
|
1679
|
+
<div class="lp-tab close-section-components-panel collapsed" onclick="toggleSectionComponentsBody()" title="Toggle components list"><i class="bi bi-chevron-down"></i></div>
|
|
1259
1680
|
</div>
|
|
1260
|
-
<div class="lp-body">
|
|
1261
|
-
<div id="tab-components" class="tab-pane"></div>
|
|
1681
|
+
<div class="lp-body collapsed">
|
|
1682
|
+
<div id="tab-components" class="tab-pane active"></div>
|
|
1262
1683
|
<div id="tab-sections" class="tab-pane"></div>
|
|
1263
1684
|
</div>
|
|
1264
1685
|
</div>
|
|
@@ -1270,7 +1691,7 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1270
1691
|
<!-- \u2500\u2500 3 main tabs \u2500\u2500 -->
|
|
1271
1692
|
<div id="main-tabs">
|
|
1272
1693
|
<button class="main-tab active" onclick="switchMainTab('design')">Design</button>
|
|
1273
|
-
<button class="main-tab" onclick="switchMainTab('states')">States</button>
|
|
1694
|
+
<button class="main-tab" style="display:none" onclick="switchMainTab('states')">States</button>
|
|
1274
1695
|
<button class="main-tab" onclick="switchMainTab('history')">History</button>
|
|
1275
1696
|
</div>
|
|
1276
1697
|
|
|
@@ -1280,15 +1701,33 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1280
1701
|
<div class="ns-icon"><i class="bi bi-cursor-text"></i></div>
|
|
1281
1702
|
Click any element on the page to edit its properties
|
|
1282
1703
|
</div>
|
|
1283
|
-
<div id="rp-accordion" style="display:none">
|
|
1704
|
+
<div id="rp-accordion" class="rp-accordion" style="display:none">
|
|
1284
1705
|
|
|
1285
1706
|
<!-- Image section \u2014 only shown when an <img> is selected -->
|
|
1286
|
-
<div class="acc-section
|
|
1707
|
+
<div class="acc-section" id="acc-image" style="display:none">
|
|
1287
1708
|
<div class="acc-hd" onclick="toggleAcc('image')">Image<i class="bi bi-chevron-right acc-arrow"></i></div>
|
|
1288
1709
|
<div class="acc-body" id="acc-body-image"></div>
|
|
1289
1710
|
</div>
|
|
1290
1711
|
|
|
1291
|
-
|
|
1712
|
+
<!-- Video section \u2014 only shown when a <video> is selected -->
|
|
1713
|
+
<div class="acc-section" id="acc-video" style="display:none">
|
|
1714
|
+
<div class="acc-hd" onclick="toggleAcc('video')">Video<i class="bi bi-chevron-right acc-arrow"></i></div>
|
|
1715
|
+
<div class="acc-body" id="acc-body-video"></div>
|
|
1716
|
+
</div>
|
|
1717
|
+
|
|
1718
|
+
<!-- YouTube section \u2014 only shown when a YouTube iframe is selected -->
|
|
1719
|
+
<div class="acc-section" id="acc-youtube" style="display:none">
|
|
1720
|
+
<div class="acc-hd" onclick="toggleAcc('youtube')">YouTube Video<i class="bi bi-chevron-right acc-arrow"></i></div>
|
|
1721
|
+
<div class="acc-body" id="acc-body-youtube"></div>
|
|
1722
|
+
</div>
|
|
1723
|
+
|
|
1724
|
+
<!-- Vimeo section \u2014 only shown when a Vimeo iframe is selected -->
|
|
1725
|
+
<div class="acc-section" id="acc-vimeo" style="display:none">
|
|
1726
|
+
<div class="acc-hd" onclick="toggleAcc('vimeo')">Vimeo Video<i class="bi bi-chevron-right acc-arrow"></i></div>
|
|
1727
|
+
<div class="acc-body" id="acc-body-vimeo"></div>
|
|
1728
|
+
</div>
|
|
1729
|
+
|
|
1730
|
+
<div class="acc-section" id="acc-content">
|
|
1292
1731
|
<div class="acc-hd" onclick="toggleAcc('content')">HTML Content<i class="bi bi-chevron-right acc-arrow"></i></div>
|
|
1293
1732
|
<div class="acc-body" id="acc-body-content"></div>
|
|
1294
1733
|
</div>
|
|
@@ -1460,28 +1899,101 @@ if (window.Vvveb && window.Vvveb.Components) {
|
|
|
1460
1899
|
|
|
1461
1900
|
// \u2500\u2500 CRO definitions + Base components \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
1462
1901
|
var CRO_SECTIONS = ${sectionsJson};
|
|
1902
|
+
var CRO_SECTION_IMAGE_ROUTE = ${JSON.stringify(CRO_SECTION_IMAGE_ROUTE)};
|
|
1903
|
+
|
|
1904
|
+
function renderCroSectionThumb(sec) {
|
|
1905
|
+
if (sec && sec.image) {
|
|
1906
|
+
return '<img src="' + CRO_SECTION_IMAGE_ROUTE + sec.image + '" alt="' + esc(sec.name || '') + '" loading="lazy">';
|
|
1907
|
+
}
|
|
1908
|
+
return sec && sec.icon ? sec.icon : '\u{1F4E6}';
|
|
1909
|
+
}
|
|
1463
1910
|
|
|
1464
1911
|
var BASE_COMPONENTS = [
|
|
1465
|
-
{ name:'Heading', icon:'bi-type-h1', html:'<h2>Your Heading</h2>' },
|
|
1466
|
-
{ name:'Paragraph', icon:'bi-paragraph', html:'<p>Your text here. Click to edit.</p>' },
|
|
1467
|
-
{ name:'Image', icon:'bi-image', html:'<img src="https://placehold.co/600x300/1a1a2e/a78bfa?text=Image" alt="Image" style="max-width:100
|
|
1468
|
-
{ name:'Button', icon:'bi-hand-index', html:'<button
|
|
1469
|
-
{ name:'Link', icon:'bi-link-45deg', html:'<a href="#">Link text</a>' },
|
|
1470
|
-
{ name:'Divider', icon:'bi-dash-lg', html:'<hr>' },
|
|
1471
|
-
{ name:'List', icon:'bi-list-ul', html:'<ul><li>Item 1</li><li>Item 2</li><li>Item 3</li></ul>' },
|
|
1472
|
-
{ name:'Video', icon:'bi-play-circle', html:'<video controls style="max-width:100
|
|
1473
|
-
{ name:'
|
|
1474
|
-
{ name:'
|
|
1475
|
-
{ name:'
|
|
1476
|
-
{ name:'
|
|
1477
|
-
{ name:'
|
|
1478
|
-
{ name:'
|
|
1479
|
-
{ name:'
|
|
1480
|
-
{ name:'
|
|
1481
|
-
{ name:'
|
|
1482
|
-
{ name:'
|
|
1912
|
+
{ name:'Heading', icon:'bi-type-h1', defaultAccSection:'content', html:'<h2 style="margin:0 0 12px;font-size:28px;font-weight:700;line-height:1.2;color:#0f172a">Your Heading</h2>' },
|
|
1913
|
+
{ name:'Paragraph', icon:'bi-paragraph', defaultAccSection:'content', html:'<p style="margin:0 0 12px;font-size:16px;line-height:1.6;color:#334155">Your text here. Click to edit.</p>' },
|
|
1914
|
+
{ 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">' },
|
|
1915
|
+
{ name:'Button', icon:'bi-hand-index', defaultAccSection:'content', 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>' },
|
|
1916
|
+
{ name:'Link', icon:'bi-link-45deg', defaultAccSection:'content', html:'<a href="#" style="font-size:16px;font-weight:500;color:#2563eb;text-decoration:underline">Link text</a>' },
|
|
1917
|
+
{ name:'Divider', icon:'bi-dash-lg', defaultAccSection:'background', html:'<hr style="margin:16px 0;border:none;border-top:1px solid #e2e8f0">' },
|
|
1918
|
+
{ name:'List', icon:'bi-list-ul', defaultAccSection:'content', 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>' },
|
|
1919
|
+
{ name:'Video', icon:'bi-play-circle', defaultAccSection:'video', html:'<video controls style="display:block;width:100%;max-width:100%;border-radius:8px;background:#000"><source src="" type="video/mp4"></video>' },
|
|
1920
|
+
{ name:'Youtube Video', icon:'bi-youtube', defaultAccSection:'youtube', 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>' },
|
|
1921
|
+
{ name:'Vimeo Video', icon:'bi-vimeo', defaultAccSection:'vimeo', 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>' },
|
|
1922
|
+
{ 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>' },
|
|
1923
|
+
{ name:'Input', icon:'bi-input-cursor-text', defaultAccSection:'content', 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">' },
|
|
1924
|
+
{ name:'Textarea', icon:'bi-textarea-resize', defaultAccSection:'content', 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>' },
|
|
1925
|
+
{ name:'Select', icon:'bi-menu-button-wide', defaultAccSection:'content', 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>' },
|
|
1926
|
+
{ name:'Card', icon:'bi-card-text', defaultAccSection:'content', 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>' },
|
|
1927
|
+
{ name:'Alert', icon:'bi-exclamation-triangle', defaultAccSection:'content', 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>' },
|
|
1928
|
+
{ name:'Badge', icon:'bi-tag', defaultAccSection:'content', 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>' },
|
|
1929
|
+
{ 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>' },
|
|
1930
|
+
{ name:'2 Cols', icon:'bi-layout-split', defaultAccSection:'spacing', html:'<div style="display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px;width:100%;box-sizing:border-box"><div style="padding:16px;background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px;min-height:80px;box-sizing:border-box"><p style="margin:0">Left column</p></div><div style="padding:16px;background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px;min-height:80px;box-sizing:border-box"><p style="margin:0">Right column</p></div></div>' },
|
|
1483
1931
|
];
|
|
1484
1932
|
|
|
1933
|
+
var baseComponentAccRegistry = null;
|
|
1934
|
+
|
|
1935
|
+
function buildBaseComponentAccRegistry() {
|
|
1936
|
+
if (baseComponentAccRegistry) return baseComponentAccRegistry;
|
|
1937
|
+
var matchers = [];
|
|
1938
|
+
var tagFallback = {};
|
|
1939
|
+
|
|
1940
|
+
BASE_COMPONENTS.forEach(function(comp) {
|
|
1941
|
+
var section = comp.defaultAccSection || 'content';
|
|
1942
|
+
var html = String(comp.html || '').trim();
|
|
1943
|
+
if (!html) return;
|
|
1944
|
+
var tagMatch = html.match(/^<([a-z0-9-]+)/i);
|
|
1945
|
+
if (!tagMatch) return;
|
|
1946
|
+
var rootTag = tagMatch[1].toLowerCase();
|
|
1947
|
+
var matcher = { tag: rootTag, section: section };
|
|
1948
|
+
|
|
1949
|
+
if (rootTag === 'div') {
|
|
1950
|
+
if (html.indexOf('role="alert"') >= 0) matcher.role = 'alert';
|
|
1951
|
+
else if (html.indexOf('repeat(2') >= 0) matcher.gridCols = 2;
|
|
1952
|
+
else if (html.indexOf('repeat(3') >= 0) matcher.gridCols = 3;
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1955
|
+
if (matcher.role || matcher.gridCols) matchers.push(matcher);
|
|
1956
|
+
else if (tagFallback[rootTag] === undefined) tagFallback[rootTag] = section;
|
|
1957
|
+
});
|
|
1958
|
+
|
|
1959
|
+
['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].forEach(function(tag) {
|
|
1960
|
+
if (tagFallback[tag] === undefined) tagFallback[tag] = tagFallback.h2 || 'content';
|
|
1961
|
+
});
|
|
1962
|
+
if (tagFallback.ol === undefined) tagFallback.ol = tagFallback.ul || 'content';
|
|
1963
|
+
|
|
1964
|
+
baseComponentAccRegistry = { matchers: matchers, tagFallback: tagFallback };
|
|
1965
|
+
return baseComponentAccRegistry;
|
|
1966
|
+
}
|
|
1967
|
+
|
|
1968
|
+
function matchesBaseComponentAccMatcher(el, matcher) {
|
|
1969
|
+
if (!el || !matcher || el.tagName.toLowerCase() !== matcher.tag) return false;
|
|
1970
|
+
if (matcher.role) return el.getAttribute('role') === matcher.role;
|
|
1971
|
+
if (matcher.gridCols) {
|
|
1972
|
+
var style = (el.getAttribute('style') || '').toLowerCase();
|
|
1973
|
+
return style.indexOf('grid-template-columns') >= 0 &&
|
|
1974
|
+
style.indexOf('repeat(' + matcher.gridCols) >= 0;
|
|
1975
|
+
}
|
|
1976
|
+
return true;
|
|
1977
|
+
}
|
|
1978
|
+
|
|
1979
|
+
function getTypeDefaultAccSection(el) {
|
|
1980
|
+
if (!el) return 'content';
|
|
1981
|
+
if (isYoutubeVideoElement(el)) return 'youtube';
|
|
1982
|
+
if (isVimeoVideoElement(el)) return 'vimeo';
|
|
1983
|
+
|
|
1984
|
+
var registry = buildBaseComponentAccRegistry();
|
|
1985
|
+
var i;
|
|
1986
|
+
for (i = 0; i < registry.matchers.length; i++) {
|
|
1987
|
+
if (matchesBaseComponentAccMatcher(el, registry.matchers[i])) {
|
|
1988
|
+
return registry.matchers[i].section;
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
|
|
1992
|
+
var tag = el.tagName.toLowerCase();
|
|
1993
|
+
if (registry.tagFallback[tag]) return registry.tagFallback[tag];
|
|
1994
|
+
return 'content';
|
|
1995
|
+
}
|
|
1996
|
+
|
|
1485
1997
|
// \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
|
|
1486
1998
|
var CHANNEL = 'vvveb-bridge';
|
|
1487
1999
|
|
|
@@ -1633,7 +2145,7 @@ var leftPanelCollapsed = false;
|
|
|
1633
2145
|
var viewportPreset = 'desktop';
|
|
1634
2146
|
var viewportWidth = 1440;
|
|
1635
2147
|
var viewportHeight = 1024;
|
|
1636
|
-
var viewportZoom =
|
|
2148
|
+
var viewportZoom = null;
|
|
1637
2149
|
var selectedEl = null;
|
|
1638
2150
|
/** Stable selector fingerprint for resilient selection recovery after DOM churn. */
|
|
1639
2151
|
var selectedElFingerprint = '';
|
|
@@ -1653,6 +2165,7 @@ var iframeSyncRetryTimer = null;
|
|
|
1653
2165
|
var iframeSyncAttempts = 0;
|
|
1654
2166
|
var selectionScrollWin = null;
|
|
1655
2167
|
var selectionResizeBound = false;
|
|
2168
|
+
var selectionPanelScrollBound = false;
|
|
1656
2169
|
var clickAttachDoc = null;
|
|
1657
2170
|
var hoverAttachDoc = null;
|
|
1658
2171
|
var changeObserver = null;
|
|
@@ -1904,16 +2417,22 @@ function clampViewportNumber(v, fallback, min, max) {
|
|
|
1904
2417
|
|
|
1905
2418
|
function getViewportFitZoom() {
|
|
1906
2419
|
var panel = document.getElementById('iframe-panel');
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
2420
|
+
if (!panel || !viewportWidth || viewportWidth <= 0 || !viewportHeight || viewportHeight <= 0) return 1;
|
|
2421
|
+
var availW = Math.max(260, panel.clientWidth);
|
|
2422
|
+
var availH = Math.max(200, panel.clientHeight);
|
|
2423
|
+
return Math.min(1, availW / viewportWidth, availH / viewportHeight);
|
|
1910
2424
|
}
|
|
1911
2425
|
|
|
1912
2426
|
function getAppliedViewportZoom() {
|
|
1913
|
-
var
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
return Math.min(
|
|
2427
|
+
var fit = getViewportFitZoom();
|
|
2428
|
+
var z = viewportZoom != null ? Number(viewportZoom) : fit;
|
|
2429
|
+
if (!Number.isFinite(z) || z <= 0) z = fit;
|
|
2430
|
+
return Math.max(0.25, Math.min(2, z));
|
|
2431
|
+
}
|
|
2432
|
+
|
|
2433
|
+
function resetViewportZoomToFit() {
|
|
2434
|
+
viewportZoom = null;
|
|
2435
|
+
applyViewportFrame();
|
|
1917
2436
|
}
|
|
1918
2437
|
|
|
1919
2438
|
function updateViewportLabel() {
|
|
@@ -1934,20 +2453,28 @@ function syncViewportMenuControls() {
|
|
|
1934
2453
|
presetButtons[i].classList.toggle('active', key === viewportPreset);
|
|
1935
2454
|
}
|
|
1936
2455
|
}
|
|
1937
|
-
if (widthInp) widthInp.value = String(viewportWidth);
|
|
1938
|
-
if (heightInp) heightInp.value = String(viewportHeight);
|
|
2456
|
+
if (widthInp && document.activeElement !== widthInp) widthInp.value = String(viewportWidth);
|
|
2457
|
+
if (heightInp && document.activeElement !== heightInp) heightInp.value = String(viewportHeight);
|
|
1939
2458
|
if (zoomInp) zoomInp.value = String(Math.round(getAppliedViewportZoom() * 100));
|
|
1940
2459
|
}
|
|
1941
2460
|
|
|
1942
2461
|
function applyViewportFrame() {
|
|
1943
2462
|
var frame = document.getElementById('device-frame');
|
|
1944
2463
|
var iframe = document.getElementById('iframeId');
|
|
2464
|
+
var panel = document.getElementById('iframe-panel');
|
|
1945
2465
|
if (!frame) return;
|
|
1946
2466
|
frame.className = currentDevice;
|
|
1947
2467
|
frame.style.width = viewportWidth + 'px';
|
|
1948
2468
|
frame.style.height = viewportHeight + 'px';
|
|
1949
2469
|
frame.style.maxWidth = 'none';
|
|
1950
|
-
|
|
2470
|
+
var zoom = getAppliedViewportZoom();
|
|
2471
|
+
var fit = getViewportFitZoom();
|
|
2472
|
+
frame.style.zoom = String(zoom);
|
|
2473
|
+
if (panel) {
|
|
2474
|
+
var zoomedIn = zoom > fit + 0.001;
|
|
2475
|
+
panel.style.overflow = zoomedIn ? 'auto' : 'hidden';
|
|
2476
|
+
panel.style.alignItems = zoomedIn ? 'flex-start' : 'center';
|
|
2477
|
+
}
|
|
1951
2478
|
if (iframe) {
|
|
1952
2479
|
iframe.style.height = viewportHeight + 'px';
|
|
1953
2480
|
iframe.style.minHeight = viewportHeight + 'px';
|
|
@@ -1964,6 +2491,7 @@ function setViewportPreset(presetKey) {
|
|
|
1964
2491
|
viewportWidth = preset.width;
|
|
1965
2492
|
viewportHeight = preset.height;
|
|
1966
2493
|
currentDevice = preset.device || 'desktop';
|
|
2494
|
+
viewportZoom = null;
|
|
1967
2495
|
['desktop','tablet','mobile'].forEach(function(d) {
|
|
1968
2496
|
document.getElementById('dev-' + d).classList.toggle('active', d === currentDevice);
|
|
1969
2497
|
});
|
|
@@ -1976,20 +2504,26 @@ function setDevice(device) {
|
|
|
1976
2504
|
var preset = DEVICE_PRESETS[device] || DEVICE_PRESETS.desktop;
|
|
1977
2505
|
viewportWidth = preset.width;
|
|
1978
2506
|
viewportHeight = preset.height;
|
|
2507
|
+
viewportZoom = null;
|
|
1979
2508
|
['desktop','tablet','mobile'].forEach(function(d) {
|
|
1980
2509
|
document.getElementById('dev-' + d).classList.toggle('active', d === device);
|
|
1981
2510
|
});
|
|
1982
2511
|
applyViewportFrame();
|
|
1983
2512
|
}
|
|
1984
2513
|
|
|
1985
|
-
function setViewportCustomFromInputs() {
|
|
2514
|
+
function setViewportCustomFromInputs(opts) {
|
|
2515
|
+
opts = opts || {};
|
|
1986
2516
|
var widthInp = document.getElementById('dev-custom-width');
|
|
1987
2517
|
var heightInp = document.getElementById('dev-custom-height');
|
|
1988
|
-
var
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
2518
|
+
var rawW = widthInp ? widthInp.value : '';
|
|
2519
|
+
var rawH = heightInp ? heightInp.value : '';
|
|
2520
|
+
if (!opts.force) {
|
|
2521
|
+
if (widthInp && document.activeElement === widthInp && rawW === '') return;
|
|
2522
|
+
if (heightInp && document.activeElement === heightInp && rawH === '') return;
|
|
2523
|
+
}
|
|
2524
|
+
viewportWidth = clampViewportNumber(rawW, viewportWidth, 240, 3840);
|
|
2525
|
+
viewportHeight = clampViewportNumber(rawH, viewportHeight, 320, 3840);
|
|
2526
|
+
viewportZoom = null;
|
|
1993
2527
|
viewportPreset = 'custom';
|
|
1994
2528
|
currentDevice = viewportWidth <= 480 ? 'mobile' : (viewportWidth <= 1024 ? 'tablet' : 'desktop');
|
|
1995
2529
|
['desktop','tablet','mobile'].forEach(function(d) {
|
|
@@ -1998,6 +2532,22 @@ function setViewportCustomFromInputs() {
|
|
|
1998
2532
|
applyViewportFrame();
|
|
1999
2533
|
}
|
|
2000
2534
|
|
|
2535
|
+
var customViewportApplyTimer = null;
|
|
2536
|
+
function scheduleCustomViewportApply() {
|
|
2537
|
+
if (customViewportApplyTimer) clearTimeout(customViewportApplyTimer);
|
|
2538
|
+
customViewportApplyTimer = setTimeout(function() {
|
|
2539
|
+
customViewportApplyTimer = null;
|
|
2540
|
+
setViewportCustomFromInputs();
|
|
2541
|
+
}, 300);
|
|
2542
|
+
}
|
|
2543
|
+
function applyCustomViewportNow() {
|
|
2544
|
+
if (customViewportApplyTimer) {
|
|
2545
|
+
clearTimeout(customViewportApplyTimer);
|
|
2546
|
+
customViewportApplyTimer = null;
|
|
2547
|
+
}
|
|
2548
|
+
setViewportCustomFromInputs({ force: true });
|
|
2549
|
+
}
|
|
2550
|
+
|
|
2001
2551
|
function closeViewportMenu() {
|
|
2002
2552
|
var menu = document.getElementById('dev-more-menu');
|
|
2003
2553
|
if (!menu) return;
|
|
@@ -2018,8 +2568,10 @@ function bindViewportControls() {
|
|
|
2018
2568
|
var menu = document.getElementById('dev-more-menu');
|
|
2019
2569
|
var leftPanelToggleLabel = document.getElementById('left-panel-toggle-label');
|
|
2020
2570
|
var presetButtons = document.querySelectorAll('#dev-preset-list .vp-preset-btn');
|
|
2021
|
-
var
|
|
2571
|
+
var widthInp = document.getElementById('dev-custom-width');
|
|
2572
|
+
var heightInp = document.getElementById('dev-custom-height');
|
|
2022
2573
|
var zoomInp = document.getElementById('dev-zoom-level');
|
|
2574
|
+
var zoomFitBtn = document.getElementById('dev-zoom-fit-btn');
|
|
2023
2575
|
var viewportBtn = document.querySelector('.tb-viewport');
|
|
2024
2576
|
function updateLeftPanelToggleLabel() {
|
|
2025
2577
|
if (!leftPanelToggleLabel) return;
|
|
@@ -2049,11 +2601,21 @@ function bindViewportControls() {
|
|
|
2049
2601
|
e.stopPropagation();
|
|
2050
2602
|
toggleViewportMenu();
|
|
2051
2603
|
});
|
|
2052
|
-
if (
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2604
|
+
if (widthInp) {
|
|
2605
|
+
widthInp.addEventListener('input', scheduleCustomViewportApply);
|
|
2606
|
+
widthInp.addEventListener('change', applyCustomViewportNow);
|
|
2607
|
+
}
|
|
2608
|
+
if (heightInp) {
|
|
2609
|
+
heightInp.addEventListener('input', scheduleCustomViewportApply);
|
|
2610
|
+
heightInp.addEventListener('change', applyCustomViewportNow);
|
|
2611
|
+
}
|
|
2612
|
+
if (zoomFitBtn) {
|
|
2613
|
+
zoomFitBtn.addEventListener('click', function(e) {
|
|
2614
|
+
e.preventDefault();
|
|
2615
|
+
e.stopPropagation();
|
|
2616
|
+
resetViewportZoomToFit();
|
|
2617
|
+
});
|
|
2618
|
+
}
|
|
2057
2619
|
if (zoomInp) {
|
|
2058
2620
|
zoomInp.addEventListener('change', function() {
|
|
2059
2621
|
var z = clampViewportNumber(zoomInp.value, Math.round(getAppliedViewportZoom() * 100), 25, 200);
|
|
@@ -2088,7 +2650,7 @@ function bindViewportControls() {
|
|
|
2088
2650
|
function switchLeftTab(tab) {
|
|
2089
2651
|
if (tab !== 'elements' && tab !== 'dom-tree') return;
|
|
2090
2652
|
currentLeftTab = tab;
|
|
2091
|
-
var tabs = document.querySelectorAll('.lp-tabs .lp-tab');
|
|
2653
|
+
var tabs = document.querySelectorAll('#left-panel .lp-tabs .lp-tab');
|
|
2092
2654
|
for (var i = 0; i < tabs.length; i++) {
|
|
2093
2655
|
var oc = tabs[i].getAttribute('onclick') || '';
|
|
2094
2656
|
tabs[i].classList.toggle('active', oc.indexOf("switchLeftTab('" + tab + "')") >= 0);
|
|
@@ -2100,18 +2662,26 @@ function switchLeftTab(tab) {
|
|
|
2100
2662
|
}
|
|
2101
2663
|
var inp = document.getElementById('comp-search');
|
|
2102
2664
|
if (tab === 'elements') {
|
|
2103
|
-
inp.placeholder = 'Search elements\u2026';
|
|
2104
2665
|
renderElementsTree(inp.value);
|
|
2105
2666
|
} else if (tab === 'dom-tree') {
|
|
2106
|
-
inp.placeholder = 'Search layers\u2026';
|
|
2107
2667
|
renderDomTree(inp.value);
|
|
2108
2668
|
}
|
|
2109
2669
|
}
|
|
2110
2670
|
|
|
2671
|
+
function expandSectionComponentsBody() {
|
|
2672
|
+
var panel = document.getElementById('section-components-panel');
|
|
2673
|
+
if (!panel) return;
|
|
2674
|
+
var body = panel.querySelector('.lp-body');
|
|
2675
|
+
var toggle = panel.querySelector('.close-section-components-panel');
|
|
2676
|
+
if (body) body.classList.remove('collapsed');
|
|
2677
|
+
if (toggle) toggle.classList.remove('collapsed');
|
|
2678
|
+
}
|
|
2679
|
+
|
|
2111
2680
|
function switchSectionComponentsTab(tab) {
|
|
2112
2681
|
if (tab !== 'components' && tab !== 'sections') return;
|
|
2682
|
+
expandSectionComponentsBody();
|
|
2113
2683
|
currentSectionComponentsTab = tab;
|
|
2114
|
-
var tabs = document.querySelectorAll('
|
|
2684
|
+
var tabs = document.querySelectorAll('#section-components-panel .lp-tabs .lp-tab');
|
|
2115
2685
|
for (var i = 0; i < tabs.length; i++) {
|
|
2116
2686
|
var oc = tabs[i].getAttribute('onclick') || '';
|
|
2117
2687
|
tabs[i].classList.toggle('active', oc.indexOf("switchSectionComponentsTab('" + tab + "')") >= 0);
|
|
@@ -2121,27 +2691,141 @@ function switchSectionComponentsTab(tab) {
|
|
|
2121
2691
|
if (compPane) compPane.classList.toggle('active', tab === 'components');
|
|
2122
2692
|
if (secPane) secPane.classList.toggle('active', tab === 'sections');
|
|
2123
2693
|
var inp = document.getElementById('comp-search');
|
|
2124
|
-
if (inp) inp.placeholder = tab === 'sections' ? 'Search
|
|
2694
|
+
if (inp) inp.placeholder = tab === 'sections' ? 'Search' : 'Search';
|
|
2125
2695
|
renderSidebar(inp ? inp.value : '');
|
|
2126
2696
|
}
|
|
2127
2697
|
|
|
2698
|
+
function toggleSectionComponentsBody() {
|
|
2699
|
+
var panel = document.getElementById('section-components-panel');
|
|
2700
|
+
if (!panel) return;
|
|
2701
|
+
var body = panel.querySelector('.lp-body');
|
|
2702
|
+
var toggle = panel.querySelector('.close-section-components-panel');
|
|
2703
|
+
if (!body) return;
|
|
2704
|
+
var collapsed = body.classList.toggle('collapsed');
|
|
2705
|
+
if (toggle) toggle.classList.toggle('collapsed', collapsed);
|
|
2706
|
+
if (!collapsed) {
|
|
2707
|
+
switchSectionComponentsTab(currentSectionComponentsTab || 'components');
|
|
2708
|
+
}
|
|
2709
|
+
}
|
|
2710
|
+
|
|
2128
2711
|
function toggleSectionComponentsPanel(forceVisible) {
|
|
2129
2712
|
var panel = document.getElementById('section-components-panel');
|
|
2130
2713
|
if (!panel) return;
|
|
2131
|
-
var
|
|
2714
|
+
var body = panel.querySelector('.lp-body');
|
|
2715
|
+
var toggle = panel.querySelector('.close-section-components-panel');
|
|
2716
|
+
if (!body) return;
|
|
2717
|
+
var isCollapsed = body.classList.contains('collapsed');
|
|
2718
|
+
var shouldExpand =
|
|
2132
2719
|
typeof forceVisible === 'boolean'
|
|
2133
2720
|
? forceVisible
|
|
2134
|
-
:
|
|
2135
|
-
|
|
2136
|
-
if (
|
|
2721
|
+
: isCollapsed;
|
|
2722
|
+
body.classList.toggle('collapsed', !shouldExpand);
|
|
2723
|
+
if (toggle) toggle.classList.toggle('collapsed', !shouldExpand);
|
|
2724
|
+
if (shouldExpand) {
|
|
2137
2725
|
switchSectionComponentsTab(currentSectionComponentsTab || 'components');
|
|
2138
2726
|
}
|
|
2139
2727
|
}
|
|
2140
2728
|
|
|
2729
|
+
function handleAddElementClick(e) {
|
|
2730
|
+
if (e) {
|
|
2731
|
+
e.preventDefault();
|
|
2732
|
+
e.stopPropagation();
|
|
2733
|
+
}
|
|
2734
|
+
toggleSectionComponentsPanel();
|
|
2735
|
+
}
|
|
2736
|
+
|
|
2141
2737
|
// \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
|
|
2738
|
+
function closeAllAccSections(exceptName) {
|
|
2739
|
+
var sections = document.querySelectorAll('#rp-accordion .acc-section');
|
|
2740
|
+
for (var i = 0; i < sections.length; i++) {
|
|
2741
|
+
var sec = sections[i];
|
|
2742
|
+
var id = sec.id || '';
|
|
2743
|
+
var name = id.replace(/^acc-/, '');
|
|
2744
|
+
if (exceptName && name === exceptName) continue;
|
|
2745
|
+
sec.classList.remove('open');
|
|
2746
|
+
}
|
|
2747
|
+
}
|
|
2748
|
+
|
|
2749
|
+
function getRpAccordion() {
|
|
2750
|
+
return document.getElementById('rp-accordion');
|
|
2751
|
+
}
|
|
2752
|
+
|
|
2753
|
+
function scrollRpAccordionContainerToTop() {
|
|
2754
|
+
var accordion = getRpAccordion();
|
|
2755
|
+
if (!accordion) return;
|
|
2756
|
+
|
|
2757
|
+
try {
|
|
2758
|
+
accordion.scrollIntoView({ block: 'start', inline: 'nearest' });
|
|
2759
|
+
} catch(_) {
|
|
2760
|
+
try { accordion.scrollIntoView(true); } catch(__) {}
|
|
2761
|
+
}
|
|
2762
|
+
|
|
2763
|
+
var node = accordion.parentElement;
|
|
2764
|
+
while (node) {
|
|
2765
|
+
try {
|
|
2766
|
+
var style = window.getComputedStyle(node);
|
|
2767
|
+
var canScroll = (style.overflowY === 'auto' || style.overflowY === 'scroll') &&
|
|
2768
|
+
node.scrollHeight > node.clientHeight;
|
|
2769
|
+
if (canScroll) {
|
|
2770
|
+
var ar = accordion.getBoundingClientRect();
|
|
2771
|
+
var nr = node.getBoundingClientRect();
|
|
2772
|
+
node.scrollTop = Math.max(0, node.scrollTop + (ar.top - nr.top));
|
|
2773
|
+
break;
|
|
2774
|
+
}
|
|
2775
|
+
} catch(_) {}
|
|
2776
|
+
node = node.parentElement;
|
|
2777
|
+
}
|
|
2778
|
+
}
|
|
2779
|
+
|
|
2780
|
+
function scrollOpenAccSectionIntoView(sec) {
|
|
2781
|
+
var accordion = getRpAccordion();
|
|
2782
|
+
if (!accordion) return;
|
|
2783
|
+
var openSec =
|
|
2784
|
+
(sec && sec.classList.contains('open') && sec.style.display !== 'none')
|
|
2785
|
+
? sec
|
|
2786
|
+
: accordion.querySelector('.acc-section.open');
|
|
2787
|
+
if (!openSec || openSec.style.display === 'none') return;
|
|
2788
|
+
|
|
2789
|
+
function doScroll() {
|
|
2790
|
+
scrollRpAccordionContainerToTop();
|
|
2791
|
+
var ar = accordion.getBoundingClientRect();
|
|
2792
|
+
var sr = openSec.getBoundingClientRect();
|
|
2793
|
+
accordion.scrollTop = Math.max(0, accordion.scrollTop + (sr.top - ar.top));
|
|
2794
|
+
}
|
|
2795
|
+
|
|
2796
|
+
requestAnimationFrame(function() {
|
|
2797
|
+
doScroll();
|
|
2798
|
+
requestAnimationFrame(function() {
|
|
2799
|
+
doScroll();
|
|
2800
|
+
setTimeout(doScroll, 0);
|
|
2801
|
+
});
|
|
2802
|
+
});
|
|
2803
|
+
}
|
|
2804
|
+
|
|
2805
|
+
function openAccSection(name, options) {
|
|
2806
|
+
if (!name) return null;
|
|
2807
|
+
var sec = document.getElementById('acc-' + name);
|
|
2808
|
+
if (!sec || sec.style.display === 'none') return null;
|
|
2809
|
+
closeAllAccSections(name);
|
|
2810
|
+
sec.classList.add('open');
|
|
2811
|
+
if (!options || options.scroll !== false) scrollOpenAccSectionIntoView(sec);
|
|
2812
|
+
return sec;
|
|
2813
|
+
}
|
|
2814
|
+
|
|
2142
2815
|
function toggleAcc(name) {
|
|
2143
2816
|
var sec = document.getElementById('acc-' + name);
|
|
2144
|
-
if (sec
|
|
2817
|
+
if (!sec || sec.style.display === 'none') return;
|
|
2818
|
+
if (sec.classList.contains('open')) {
|
|
2819
|
+
sec.classList.remove('open');
|
|
2820
|
+
return;
|
|
2821
|
+
}
|
|
2822
|
+
openAccSection(name);
|
|
2823
|
+
}
|
|
2824
|
+
|
|
2825
|
+
function focusDesignAccordionSection(name) {
|
|
2826
|
+
if (!name) return;
|
|
2827
|
+
if (currentMainTab !== 'design') switchMainTab('design');
|
|
2828
|
+
openAccSection(name);
|
|
2145
2829
|
}
|
|
2146
2830
|
|
|
2147
2831
|
// \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
|
|
@@ -2208,9 +2892,20 @@ var PROP_META = {
|
|
|
2208
2892
|
'pp-id': {label:'ID', cssProp:null},
|
|
2209
2893
|
'pp-href': {label:'Href', cssProp:null},
|
|
2210
2894
|
'pp-target': {label:'Target', cssProp:null},
|
|
2895
|
+
'pp-rel': {label:'Rel', cssProp:null},
|
|
2896
|
+
'pp-download':{label:'Download', cssProp:null},
|
|
2897
|
+
'pp-link-title': {label:'Title', cssProp:null},
|
|
2898
|
+
'pp-hreflang':{label:'Hreflang', cssProp:null},
|
|
2899
|
+
'pp-link-type': {label:'Link type', cssProp:null},
|
|
2900
|
+
'pp-referrerpolicy': {label:'Referrer policy', cssProp:null},
|
|
2211
2901
|
'pp-src': {label:'Src', cssProp:null},
|
|
2902
|
+
'pp-video-src': {label:'Src', cssProp:null},
|
|
2903
|
+
'pp-video-poster': {label:'Poster', cssProp:null},
|
|
2904
|
+
'pp-youtube-id': {label:'YouTube video ID', cssProp:null},
|
|
2905
|
+
'pp-vimeo-id': {label:'Vimeo video ID', cssProp:null},
|
|
2212
2906
|
'pp-alt': {label:'Alt', cssProp:null},
|
|
2213
2907
|
'pp-ph': {label:'Placeholder', cssProp:null},
|
|
2908
|
+
'pp-value': {label:'Value', cssProp:null},
|
|
2214
2909
|
'pp-text': {label:'Inner text', cssProp:null},
|
|
2215
2910
|
'pp-html': {label:'Inner HTML', cssProp:null},
|
|
2216
2911
|
'pp-mob-css': {label:'Mobile CSS', cssProp:null},
|
|
@@ -2233,9 +2928,20 @@ function getOriginalValue(inputId, el) {
|
|
|
2233
2928
|
case 'pp-id': return el.id || '';
|
|
2234
2929
|
case 'pp-href': return el.getAttribute('href') || '';
|
|
2235
2930
|
case 'pp-target': return el.getAttribute('target') || '';
|
|
2931
|
+
case 'pp-rel': return el.getAttribute('rel') || '';
|
|
2932
|
+
case 'pp-download': return el.getAttribute('download') || '';
|
|
2933
|
+
case 'pp-link-title': return el.getAttribute('title') || '';
|
|
2934
|
+
case 'pp-hreflang': return el.getAttribute('hreflang') || '';
|
|
2935
|
+
case 'pp-link-type': return el.getAttribute('type') || '';
|
|
2936
|
+
case 'pp-referrerpolicy': return el.getAttribute('referrerpolicy') || '';
|
|
2236
2937
|
case 'pp-src': return el.getAttribute('src') || '';
|
|
2938
|
+
case 'pp-video-src': return getVideoSrc(el);
|
|
2939
|
+
case 'pp-video-poster': return el.getAttribute('poster') || '';
|
|
2940
|
+
case 'pp-youtube-id': return getYoutubeVideoId(el);
|
|
2941
|
+
case 'pp-vimeo-id': return getVimeoVideoId(el);
|
|
2237
2942
|
case 'pp-alt': return el.getAttribute('alt') || '';
|
|
2238
2943
|
case 'pp-ph': return el.getAttribute('placeholder') || '';
|
|
2944
|
+
case 'pp-value': return getFormControlValue(el);
|
|
2239
2945
|
case 'pp-css': return el.getAttribute('style') || '';
|
|
2240
2946
|
case 'pp-mob-css': return el.dataset.mobileCss || '';
|
|
2241
2947
|
case 'pp-tab-css': return el.dataset.tabletCss || '';
|
|
@@ -2372,9 +3078,20 @@ function revertChangeOnDom(change) {
|
|
|
2372
3078
|
case 'pp-css': orig ? el.setAttribute('style', orig) : el.removeAttribute('style'); break;
|
|
2373
3079
|
case 'pp-href': orig ? el.setAttribute('href', orig) : el.removeAttribute('href'); break;
|
|
2374
3080
|
case 'pp-target': orig ? el.setAttribute('target', orig) : el.removeAttribute('target'); break;
|
|
3081
|
+
case 'pp-rel': orig ? el.setAttribute('rel', orig) : el.removeAttribute('rel'); break;
|
|
3082
|
+
case 'pp-download': orig ? el.setAttribute('download', orig) : el.removeAttribute('download'); break;
|
|
3083
|
+
case 'pp-link-title': orig ? el.setAttribute('title', orig) : el.removeAttribute('title'); break;
|
|
3084
|
+
case 'pp-hreflang': orig ? el.setAttribute('hreflang', orig) : el.removeAttribute('hreflang'); break;
|
|
3085
|
+
case 'pp-link-type': orig ? el.setAttribute('type', orig) : el.removeAttribute('type'); break;
|
|
3086
|
+
case 'pp-referrerpolicy': orig ? el.setAttribute('referrerpolicy', orig) : el.removeAttribute('referrerpolicy'); break;
|
|
2375
3087
|
case 'pp-src': orig ? el.setAttribute('src', orig) : el.removeAttribute('src'); break;
|
|
3088
|
+
case 'pp-video-src': orig ? setVideoSrc(el, orig) : setVideoSrc(el, ''); break;
|
|
3089
|
+
case 'pp-video-poster': orig ? el.setAttribute('poster', orig) : el.removeAttribute('poster'); break;
|
|
3090
|
+
case 'pp-youtube-id': orig ? setYoutubeVideoId(el, orig) : setYoutubeVideoId(el, ''); break;
|
|
3091
|
+
case 'pp-vimeo-id': orig ? setVimeoVideoId(el, orig) : setVimeoVideoId(el, ''); break;
|
|
2376
3092
|
case 'pp-alt': orig ? el.setAttribute('alt', orig) : el.removeAttribute('alt'); break;
|
|
2377
3093
|
case 'pp-ph': orig ? el.setAttribute('placeholder', orig) : el.removeAttribute('placeholder'); break;
|
|
3094
|
+
case 'pp-value': el.value = orig; break;
|
|
2378
3095
|
case 'pp-mob-css': el.dataset.mobileCss = orig; break;
|
|
2379
3096
|
case 'pp-tab-css': el.dataset.tabletCss = orig; break;
|
|
2380
3097
|
default: console.warn('[V2] revertChangeOnDom: no revert handler for', change.inputId);
|
|
@@ -2398,11 +3115,28 @@ function syncDesignInput(change) {
|
|
|
2398
3115
|
function removeStateChange(idx) {
|
|
2399
3116
|
var change = stateChanges[idx];
|
|
2400
3117
|
if (!change) return;
|
|
3118
|
+
if (
|
|
3119
|
+
change.isStructuralLive &&
|
|
3120
|
+
normalizeChangesetType({ type: change.structuralType }) === 'insert'
|
|
3121
|
+
) {
|
|
3122
|
+
var instId = historyInsertInstanceId(null, change);
|
|
3123
|
+
if (instId) {
|
|
3124
|
+
removeEditorInsertByInstanceId(instId);
|
|
3125
|
+
commitStateChangesForActiveVariation();
|
|
3126
|
+
renderStatesTab();
|
|
3127
|
+
if (currentMainTab === 'history') renderHistoryTab();
|
|
3128
|
+
try {
|
|
3129
|
+
delete varHtmlCache[activeVarId];
|
|
3130
|
+
} catch(_) {}
|
|
3131
|
+
saveCurrentVariationHtml();
|
|
3132
|
+
recomputeEditorDirty();
|
|
3133
|
+
scheduleDomTreeRefresh();
|
|
3134
|
+
return;
|
|
3135
|
+
}
|
|
3136
|
+
}
|
|
2401
3137
|
if (change.isStructuralLive) {
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
change.vveTs,
|
|
2405
|
-
);
|
|
3138
|
+
var varId = change.structuralVarId || activeVarId;
|
|
3139
|
+
removeSessionStructuralRowByTimestamp(varId, change.vveTs);
|
|
2406
3140
|
stateChanges.splice(idx, 1);
|
|
2407
3141
|
commitStateChangesForActiveVariation();
|
|
2408
3142
|
renderStatesTab();
|
|
@@ -2500,10 +3234,28 @@ function captureChangesetSnapshotBeforeApply(entry, el, iframeDoc) {
|
|
|
2500
3234
|
break;
|
|
2501
3235
|
case 'attribute':
|
|
2502
3236
|
if (entry.attribute) {
|
|
3237
|
+
var attrVal = el.getAttribute(entry.attribute);
|
|
3238
|
+
if (
|
|
3239
|
+
String(entry.attribute).toLowerCase() === 'src' &&
|
|
3240
|
+
el.tagName &&
|
|
3241
|
+
el.tagName.toLowerCase() === 'video'
|
|
3242
|
+
) {
|
|
3243
|
+
attrVal = getVideoSrc(el);
|
|
3244
|
+
} else if (
|
|
3245
|
+
String(entry.attribute).toLowerCase() === 'data-youtube-id' &&
|
|
3246
|
+
isYoutubeVideoElement(el)
|
|
3247
|
+
) {
|
|
3248
|
+
attrVal = getYoutubeVideoId(el);
|
|
3249
|
+
} else if (
|
|
3250
|
+
String(entry.attribute).toLowerCase() === 'data-vimeo-id' &&
|
|
3251
|
+
isVimeoVideoElement(el)
|
|
3252
|
+
) {
|
|
3253
|
+
attrVal = getVimeoVideoId(el);
|
|
3254
|
+
}
|
|
2503
3255
|
appliedChangesetSnapshots[k] = {
|
|
2504
3256
|
kind: 'attribute',
|
|
2505
3257
|
name: entry.attribute,
|
|
2506
|
-
v:
|
|
3258
|
+
v: attrVal,
|
|
2507
3259
|
};
|
|
2508
3260
|
}
|
|
2509
3261
|
break;
|
|
@@ -2552,6 +3304,13 @@ function revertChangesetEntryOnDom(entry) {
|
|
|
2552
3304
|
var iframeDoc = document.getElementById('iframeId').contentDocument;
|
|
2553
3305
|
if (!iframeDoc) return false;
|
|
2554
3306
|
var k = entrySnapshotKey(entry);
|
|
3307
|
+
if (normalizeChangesetType(entry) === 'insert') {
|
|
3308
|
+
var instId = instanceIdFromInsertHtml(entry.html);
|
|
3309
|
+
delete appliedChangesetSnapshots[k];
|
|
3310
|
+
if (instId && removeEditorInsertByInstanceId(instId)) return false;
|
|
3311
|
+
softReloadEditorIframe();
|
|
3312
|
+
return true;
|
|
3313
|
+
}
|
|
2555
3314
|
var snap = appliedChangesetSnapshots[k];
|
|
2556
3315
|
var el = querySelectorResolved(iframeDoc, entry.selector);
|
|
2557
3316
|
if (!snap || !el) {
|
|
@@ -2570,7 +3329,23 @@ function revertChangesetEntryOnDom(entry) {
|
|
|
2570
3329
|
if (snap.v) el.setAttribute('style', snap.v);
|
|
2571
3330
|
else el.removeAttribute('style');
|
|
2572
3331
|
} else if (snap.kind === 'attribute' && snap.name) {
|
|
2573
|
-
if (
|
|
3332
|
+
if (
|
|
3333
|
+
String(snap.name).toLowerCase() === 'src' &&
|
|
3334
|
+
el.tagName &&
|
|
3335
|
+
el.tagName.toLowerCase() === 'video'
|
|
3336
|
+
) {
|
|
3337
|
+
setVideoSrc(el, snap.v == null ? '' : snap.v);
|
|
3338
|
+
} else if (
|
|
3339
|
+
String(snap.name).toLowerCase() === 'data-youtube-id' &&
|
|
3340
|
+
isYoutubeVideoElement(el)
|
|
3341
|
+
) {
|
|
3342
|
+
setYoutubeVideoId(el, snap.v == null ? '' : snap.v);
|
|
3343
|
+
} else if (
|
|
3344
|
+
String(snap.name).toLowerCase() === 'data-vimeo-id' &&
|
|
3345
|
+
isVimeoVideoElement(el)
|
|
3346
|
+
) {
|
|
3347
|
+
setVimeoVideoId(el, snap.v == null ? '' : snap.v);
|
|
3348
|
+
} else if (snap.v == null || snap.v === '') el.removeAttribute(snap.name);
|
|
2574
3349
|
else el.setAttribute(snap.name, snap.v);
|
|
2575
3350
|
} else if (snap.kind === 'display') el.style.display = snap.v;
|
|
2576
3351
|
else {
|
|
@@ -2651,6 +3426,42 @@ function formatHistoryRelativeTime(ts) {
|
|
|
2651
3426
|
return day + ' day' + (day === 1 ? '' : 's') + ' ago';
|
|
2652
3427
|
}
|
|
2653
3428
|
|
|
3429
|
+
function findSessionInsertRowForChange(change) {
|
|
3430
|
+
if (!change) return null;
|
|
3431
|
+
var varId = change.structuralVarId || activeVarId;
|
|
3432
|
+
var arr = varId && sessionStructuralChainRowsByVarId[varId];
|
|
3433
|
+
if (!arr || !arr.length) return null;
|
|
3434
|
+
var instId = '';
|
|
3435
|
+
try {
|
|
3436
|
+
if (change.targetEl && change.targetEl.getAttribute) {
|
|
3437
|
+
instId = change.targetEl.getAttribute('data-vve-instance') || '';
|
|
3438
|
+
}
|
|
3439
|
+
} catch(_) {}
|
|
3440
|
+
for (var i = 0; i < arr.length; i++) {
|
|
3441
|
+
var row = arr[i];
|
|
3442
|
+
if (!row || normalizeChangesetType(row) !== 'insert') continue;
|
|
3443
|
+
if (change.vveTs && row.vveTs === change.vveTs) return row;
|
|
3444
|
+
if (instId && instanceIdFromInsertHtml(row.html) === instId) return row;
|
|
3445
|
+
}
|
|
3446
|
+
return null;
|
|
3447
|
+
}
|
|
3448
|
+
|
|
3449
|
+
function historyInsertInstanceId(entry, change) {
|
|
3450
|
+
if (entry && normalizeChangesetType(entry) === 'insert') {
|
|
3451
|
+
return instanceIdFromInsertHtml(entry.html);
|
|
3452
|
+
}
|
|
3453
|
+
if (change && change.isStructuralLive && normalizeChangesetType({ type: change.structuralType }) === 'insert') {
|
|
3454
|
+
var row = findSessionInsertRowForChange(change);
|
|
3455
|
+
if (row) return instanceIdFromInsertHtml(row.html);
|
|
3456
|
+
try {
|
|
3457
|
+
if (change.targetEl && change.targetEl.getAttribute) {
|
|
3458
|
+
return change.targetEl.getAttribute('data-vve-instance') || '';
|
|
3459
|
+
}
|
|
3460
|
+
} catch(_) {}
|
|
3461
|
+
}
|
|
3462
|
+
return '';
|
|
3463
|
+
}
|
|
3464
|
+
|
|
2654
3465
|
function getUnifiedHistoryItems() {
|
|
2655
3466
|
var out = [];
|
|
2656
3467
|
var v = getActiveVariationForHistory();
|
|
@@ -2660,6 +3471,7 @@ function getUnifiedHistoryItems() {
|
|
|
2660
3471
|
out.push({
|
|
2661
3472
|
source: 'saved',
|
|
2662
3473
|
idx: i,
|
|
3474
|
+
insertInstanceId: historyInsertInstanceId(e, null),
|
|
2663
3475
|
selector: (e && e.selector) || '(unknown)',
|
|
2664
3476
|
label: historyEntryTypeLabel(e),
|
|
2665
3477
|
value: historyEntryValuePreview(e),
|
|
@@ -2676,6 +3488,7 @@ function getUnifiedHistoryItems() {
|
|
|
2676
3488
|
out.push({
|
|
2677
3489
|
source: 'live',
|
|
2678
3490
|
idx: j,
|
|
3491
|
+
insertInstanceId: historyInsertInstanceId(null, c),
|
|
2679
3492
|
selector: c.selector || '(unknown)',
|
|
2680
3493
|
label: c.label || 'Live change',
|
|
2681
3494
|
value: c.value != null ? String(c.value).slice(0, 120) : '',
|
|
@@ -2709,11 +3522,15 @@ function renderHistoryTab() {
|
|
|
2709
3522
|
var title = 'Edit - ' + (it.label || 'Change');
|
|
2710
3523
|
var avatarLabel = it.source === 'live' ? 'Y' : 'S';
|
|
2711
3524
|
var timeText = formatHistoryRelativeTime(it.ts) || (it.tsLabel || '');
|
|
3525
|
+
var removeOnclick = it.insertInstanceId
|
|
3526
|
+
? 'removeHistoryItem("' + esc(it.source) + '",' + it.idx + ', event, "' + esc(it.insertInstanceId) + '")'
|
|
3527
|
+
: 'removeHistoryItem("' + esc(it.source) + '",' + it.idx + ', event)';
|
|
2712
3528
|
html +=
|
|
2713
3529
|
'<div class="history-item" role="button" tabindex="0" title="Jump to element in iframe" onclick="focusHistoryItem("' +
|
|
2714
3530
|
esc(it.source) +
|
|
2715
3531
|
'",' +
|
|
2716
3532
|
it.idx +
|
|
3533
|
+
(it.insertInstanceId ? ', "' + esc(it.insertInstanceId) + '"' : '') +
|
|
2717
3534
|
')">' +
|
|
2718
3535
|
'<span class="history-dot"></span>' +
|
|
2719
3536
|
'<div class="history-card">' +
|
|
@@ -2724,18 +3541,16 @@ function renderHistoryTab() {
|
|
|
2724
3541
|
'</div>' +
|
|
2725
3542
|
'<div class="history-time">' + esc(timeText || 'n/a') + '</div>' +
|
|
2726
3543
|
'</div>' +
|
|
2727
|
-
'<button type="button" class="state-remove history-remove" title="Remove this change" onclick="
|
|
2728
|
-
|
|
2729
|
-
'
|
|
2730
|
-
it.idx +
|
|
2731
|
-
', event)">✕</button>' +
|
|
3544
|
+
'<button type="button" class="state-remove history-remove" title="Remove this change" onclick="' +
|
|
3545
|
+
removeOnclick +
|
|
3546
|
+
'">✕</button>' +
|
|
2732
3547
|
'</div>';
|
|
2733
3548
|
}
|
|
2734
3549
|
html += '</div>';
|
|
2735
3550
|
container.innerHTML = html;
|
|
2736
3551
|
}
|
|
2737
3552
|
|
|
2738
|
-
function focusHistoryItem(source, idx) {
|
|
3553
|
+
function focusHistoryItem(source, idx, insertInstanceId) {
|
|
2739
3554
|
if (source === 'live') {
|
|
2740
3555
|
var change = stateChanges[idx];
|
|
2741
3556
|
if (!change || !change.selector) return;
|
|
@@ -2743,6 +3558,20 @@ function focusHistoryItem(source, idx) {
|
|
|
2743
3558
|
var iframe = document.getElementById('iframeId');
|
|
2744
3559
|
var iframeDoc = iframe && iframe.contentDocument;
|
|
2745
3560
|
if (!iframeDoc) return;
|
|
3561
|
+
var instId = insertInstanceId || historyInsertInstanceId(null, change);
|
|
3562
|
+
if (instId) {
|
|
3563
|
+
var safeInst = String(instId).split('"').join('\\"');
|
|
3564
|
+
var insertedEl = iframeDoc.querySelector('[data-vve-instance="' + safeInst + '"]');
|
|
3565
|
+
if (insertedEl) {
|
|
3566
|
+
selectElement(insertedEl);
|
|
3567
|
+
try {
|
|
3568
|
+
insertedEl.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'nearest' });
|
|
3569
|
+
} catch(_) {
|
|
3570
|
+
insertedEl.scrollIntoView();
|
|
3571
|
+
}
|
|
3572
|
+
return;
|
|
3573
|
+
}
|
|
3574
|
+
}
|
|
2746
3575
|
var el = querySelectorResolved(iframeDoc, change.selector);
|
|
2747
3576
|
if (!el) return;
|
|
2748
3577
|
selectElement(el);
|
|
@@ -2754,12 +3583,25 @@ function focusHistoryItem(source, idx) {
|
|
|
2754
3583
|
} catch(_) {}
|
|
2755
3584
|
return;
|
|
2756
3585
|
}
|
|
2757
|
-
focusHistoryChangeset(idx);
|
|
3586
|
+
focusHistoryChangeset(idx, insertInstanceId);
|
|
2758
3587
|
}
|
|
2759
3588
|
|
|
2760
|
-
function removeHistoryItem(source, idx, evt) {
|
|
3589
|
+
function removeHistoryItem(source, idx, evt, insertInstanceId) {
|
|
3590
|
+
if (evt && evt.stopPropagation) evt.stopPropagation();
|
|
3591
|
+
if (insertInstanceId) {
|
|
3592
|
+
removeEditorInsertByInstanceId(insertInstanceId);
|
|
3593
|
+
commitStateChangesForActiveVariation();
|
|
3594
|
+
try {
|
|
3595
|
+
delete varHtmlCache[activeVarId];
|
|
3596
|
+
} catch(_) {}
|
|
3597
|
+
saveCurrentVariationHtml();
|
|
3598
|
+
recomputeEditorDirty();
|
|
3599
|
+
if (currentMainTab === 'states') renderStatesTab();
|
|
3600
|
+
if (currentMainTab === 'history') renderHistoryTab();
|
|
3601
|
+
scheduleDomTreeRefresh();
|
|
3602
|
+
return;
|
|
3603
|
+
}
|
|
2761
3604
|
if (source === 'live') {
|
|
2762
|
-
if (evt && evt.stopPropagation) evt.stopPropagation();
|
|
2763
3605
|
removeStateChange(idx);
|
|
2764
3606
|
if (currentMainTab === 'history') renderHistoryTab();
|
|
2765
3607
|
return;
|
|
@@ -2798,7 +3640,7 @@ function isStyleOnlyChangesetEntry(entry) {
|
|
|
2798
3640
|
return false;
|
|
2799
3641
|
}
|
|
2800
3642
|
|
|
2801
|
-
function focusHistoryChangeset(idx) {
|
|
3643
|
+
function focusHistoryChangeset(idx, insertInstanceId) {
|
|
2802
3644
|
var v = getActiveVariationForHistory();
|
|
2803
3645
|
if (!v) return;
|
|
2804
3646
|
var arr = parseVariationChangesets(v);
|
|
@@ -2809,6 +3651,20 @@ function focusHistoryChangeset(idx) {
|
|
|
2809
3651
|
var iframe = document.getElementById('iframeId');
|
|
2810
3652
|
var iframeDoc = iframe && iframe.contentDocument;
|
|
2811
3653
|
if (!iframeDoc) return;
|
|
3654
|
+
var instId = insertInstanceId || historyInsertInstanceId(entry, null);
|
|
3655
|
+
if (instId) {
|
|
3656
|
+
var safeInst = String(instId).split('"').join('\\"');
|
|
3657
|
+
var insertedEl = iframeDoc.querySelector('[data-vve-instance="' + safeInst + '"]');
|
|
3658
|
+
if (insertedEl) {
|
|
3659
|
+
selectElement(insertedEl);
|
|
3660
|
+
try {
|
|
3661
|
+
insertedEl.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'nearest' });
|
|
3662
|
+
} catch(_) {
|
|
3663
|
+
insertedEl.scrollIntoView();
|
|
3664
|
+
}
|
|
3665
|
+
return;
|
|
3666
|
+
}
|
|
3667
|
+
}
|
|
2812
3668
|
var el = querySelectorResolved(iframeDoc, entry.selector);
|
|
2813
3669
|
if (!el) return;
|
|
2814
3670
|
selectElement(el);
|
|
@@ -2850,6 +3706,10 @@ function removeHistoryChangeset(idx, evt) {
|
|
|
2850
3706
|
var removedIsStructural = removedType === 'insert' || removedType === 'reorder';
|
|
2851
3707
|
if (didReload) {
|
|
2852
3708
|
/* revertChangesetEntryOnDom already kicked off iframe reload */
|
|
3709
|
+
} else if (removedType === 'insert') {
|
|
3710
|
+
try {
|
|
3711
|
+
saveCurrentVariationHtml();
|
|
3712
|
+
} catch(_) {}
|
|
2853
3713
|
} else if (removedIsStructural) {
|
|
2854
3714
|
softReloadEditorIframe();
|
|
2855
3715
|
} else if (hasStructuralRemaining) {
|
|
@@ -3518,6 +4378,14 @@ function loadPage(proxyUrl) {
|
|
|
3518
4378
|
// \u2500\u2500 Variation management \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
3519
4379
|
var VAR_COLORS = ['#0069A8','#CA3500','#00786F','#ec4899','#14b8a6','#f59e0b','#8b5cf6','#ef4444'];
|
|
3520
4380
|
|
|
4381
|
+
function varColorAlpha(hex, alpha) {
|
|
4382
|
+
var h = hex.slice(1);
|
|
4383
|
+
return 'rgba(' +
|
|
4384
|
+
parseInt(h.slice(0, 2), 16) + ',' +
|
|
4385
|
+
parseInt(h.slice(2, 4), 16) + ',' +
|
|
4386
|
+
parseInt(h.slice(4, 6), 16) + ',' + alpha + ')';
|
|
4387
|
+
}
|
|
4388
|
+
|
|
3521
4389
|
function renderVariationTabs() {
|
|
3522
4390
|
var container = document.getElementById('variation-tabs');
|
|
3523
4391
|
container.innerHTML = '';
|
|
@@ -3529,7 +4397,12 @@ function renderVariationTabs() {
|
|
|
3529
4397
|
btn.onclick = function() { switchVariation(v._id); };
|
|
3530
4398
|
var dot = document.createElement('span');
|
|
3531
4399
|
dot.className = 'var-dot';
|
|
3532
|
-
|
|
4400
|
+
var color = VAR_COLORS[i % VAR_COLORS.length];
|
|
4401
|
+
btn.setAttribute('data-color', color);
|
|
4402
|
+
btn.style.setProperty('--var-tab-color', color);
|
|
4403
|
+
dot.setAttribute('data-color', color);
|
|
4404
|
+
dot.style.background = color;
|
|
4405
|
+
dot.style.boxShadow = '0 0 0 3px ' + varColorAlpha(color, 0.5);
|
|
3533
4406
|
btn.appendChild(dot);
|
|
3534
4407
|
btn.appendChild(document.createTextNode(label));
|
|
3535
4408
|
container.appendChild(btn);
|
|
@@ -3730,6 +4603,29 @@ function removeSessionStructuralRowByTimestamp(varId, ts) {
|
|
|
3730
4603
|
}
|
|
3731
4604
|
}
|
|
3732
4605
|
|
|
4606
|
+
function removeStructuralStateChangeByTimestamp(varId, ts) {
|
|
4607
|
+
if (!varId || !ts) return;
|
|
4608
|
+
for (var i = stateChanges.length - 1; i >= 0; i--) {
|
|
4609
|
+
var c = stateChanges[i];
|
|
4610
|
+
if (
|
|
4611
|
+
c &&
|
|
4612
|
+
c.isStructuralLive &&
|
|
4613
|
+
c.vveTs === ts &&
|
|
4614
|
+
(c.structuralVarId || activeVarId) === varId
|
|
4615
|
+
) {
|
|
4616
|
+
stateChanges.splice(i, 1);
|
|
4617
|
+
}
|
|
4618
|
+
}
|
|
4619
|
+
}
|
|
4620
|
+
|
|
4621
|
+
/** Undo a session insert when its root node is deleted \u2014 avoids orphan remove rows that match re-inserts at the same slot. */
|
|
4622
|
+
function cancelSessionInsertForElement(varId, el) {
|
|
4623
|
+
if (!varId || !el) return false;
|
|
4624
|
+
var inst = el.getAttribute && el.getAttribute('data-vve-instance');
|
|
4625
|
+
if (!inst || !String(inst).trim()) return false;
|
|
4626
|
+
return removeEditorInsertByInstanceId(inst, { skipDom: true, varId: varId });
|
|
4627
|
+
}
|
|
4628
|
+
|
|
3733
4629
|
/** One States-tab row -> Conversion.io chain-set shape (matches applyChangesetEntry). */
|
|
3734
4630
|
function stateChangeToChainSet(c) {
|
|
3735
4631
|
if (!c || !c.selector) return null;
|
|
@@ -3755,12 +4651,34 @@ function stateChangeToChainSet(c) {
|
|
|
3755
4651
|
return { selector: c.selector, type: 'attribute', attribute: 'href', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
3756
4652
|
case 'pp-target':
|
|
3757
4653
|
return { selector: c.selector, type: 'attribute', attribute: 'target', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4654
|
+
case 'pp-rel':
|
|
4655
|
+
return { selector: c.selector, type: 'attribute', attribute: 'rel', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4656
|
+
case 'pp-download':
|
|
4657
|
+
return { selector: c.selector, type: 'attribute', attribute: 'download', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4658
|
+
case 'pp-link-title':
|
|
4659
|
+
return { selector: c.selector, type: 'attribute', attribute: 'title', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4660
|
+
case 'pp-hreflang':
|
|
4661
|
+
return { selector: c.selector, type: 'attribute', attribute: 'hreflang', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4662
|
+
case 'pp-link-type':
|
|
4663
|
+
return { selector: c.selector, type: 'attribute', attribute: 'type', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4664
|
+
case 'pp-referrerpolicy':
|
|
4665
|
+
return { selector: c.selector, type: 'attribute', attribute: 'referrerpolicy', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
3758
4666
|
case 'pp-src':
|
|
3759
4667
|
return { selector: c.selector, type: 'attribute', attribute: 'src', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4668
|
+
case 'pp-video-src':
|
|
4669
|
+
return { selector: c.selector, type: 'attribute', attribute: 'src', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4670
|
+
case 'pp-video-poster':
|
|
4671
|
+
return { selector: c.selector, type: 'attribute', attribute: 'poster', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4672
|
+
case 'pp-youtube-id':
|
|
4673
|
+
return { selector: c.selector, type: 'attribute', attribute: 'data-youtube-id', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4674
|
+
case 'pp-vimeo-id':
|
|
4675
|
+
return { selector: c.selector, type: 'attribute', attribute: 'data-vimeo-id', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
3760
4676
|
case 'pp-alt':
|
|
3761
4677
|
return { selector: c.selector, type: 'attribute', attribute: 'alt', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
3762
4678
|
case 'pp-ph':
|
|
3763
4679
|
return { selector: c.selector, type: 'attribute', attribute: 'placeholder', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4680
|
+
case 'pp-value':
|
|
4681
|
+
return { selector: c.selector, type: 'attribute', attribute: 'value', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
3764
4682
|
case 'pp-css':
|
|
3765
4683
|
return { selector: c.selector, type: 'attribute', attribute: 'style', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
3766
4684
|
case 'pp-mob-css':
|
|
@@ -4020,7 +4938,25 @@ function applyChangesetEntry(entry, iframeDoc) {
|
|
|
4020
4938
|
case 'attribute':
|
|
4021
4939
|
if (entry.attribute && entry.value != null) {
|
|
4022
4940
|
if (String(entry.attribute).toLowerCase() === 'style') break;
|
|
4023
|
-
|
|
4941
|
+
if (
|
|
4942
|
+
String(entry.attribute).toLowerCase() === 'src' &&
|
|
4943
|
+
el.tagName &&
|
|
4944
|
+
el.tagName.toLowerCase() === 'video'
|
|
4945
|
+
) {
|
|
4946
|
+
setVideoSrc(el, entry.value);
|
|
4947
|
+
} else if (
|
|
4948
|
+
String(entry.attribute).toLowerCase() === 'data-youtube-id' &&
|
|
4949
|
+
isYoutubeVideoElement(el)
|
|
4950
|
+
) {
|
|
4951
|
+
setYoutubeVideoId(el, entry.value);
|
|
4952
|
+
} else if (
|
|
4953
|
+
String(entry.attribute).toLowerCase() === 'data-vimeo-id' &&
|
|
4954
|
+
isVimeoVideoElement(el)
|
|
4955
|
+
) {
|
|
4956
|
+
setVimeoVideoId(el, entry.value);
|
|
4957
|
+
} else {
|
|
4958
|
+
el.setAttribute(entry.attribute, entry.value);
|
|
4959
|
+
}
|
|
4024
4960
|
}
|
|
4025
4961
|
break;
|
|
4026
4962
|
case 'insert': {
|
|
@@ -4029,9 +4965,12 @@ function applyChangesetEntry(entry, iframeDoc) {
|
|
|
4029
4965
|
if (structuralDedupeKey) appliedStructuralChangesetKeys[structuralDedupeKey] = true;
|
|
4030
4966
|
break;
|
|
4031
4967
|
}
|
|
4032
|
-
case 'remove':
|
|
4968
|
+
case 'remove': {
|
|
4969
|
+
var inst = el.getAttribute && el.getAttribute('data-vve-instance');
|
|
4970
|
+
if (inst && String(entry.selector || '').indexOf('data-vve-instance') < 0) break;
|
|
4033
4971
|
el.style.display = 'none';
|
|
4034
4972
|
break;
|
|
4973
|
+
}
|
|
4035
4974
|
case 'reorder': {
|
|
4036
4975
|
var target = entry.targetSelector ? querySelectorResolved(iframeDoc, entry.targetSelector) : null;
|
|
4037
4976
|
if (!target || !el.parentNode || !target.parentNode) break;
|
|
@@ -4208,7 +5147,7 @@ function startIframeContentApplyWatcher(navGen, prevDocRef) {
|
|
|
4208
5147
|
}
|
|
4209
5148
|
|
|
4210
5149
|
// \u2500\u2500 Element selection \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
4211
|
-
function selectElement(el) {
|
|
5150
|
+
function selectElement(el, options) {
|
|
4212
5151
|
beginSuppressIframeMutationDirty();
|
|
4213
5152
|
try {
|
|
4214
5153
|
if (selectedEl) { try { selectedEl.classList.remove('vve-selected'); } catch(_) {} }
|
|
@@ -4222,7 +5161,7 @@ function selectElement(el) {
|
|
|
4222
5161
|
document.getElementById('bc-path').textContent = buildSelector(el);
|
|
4223
5162
|
document.getElementById('bc-path').style.color = 'var(--accent-txt)';
|
|
4224
5163
|
document.getElementById('no-sel').style.display = 'none';
|
|
4225
|
-
renderRightPanel(el);
|
|
5164
|
+
renderRightPanel(el, options);
|
|
4226
5165
|
updateSelectionToolbar();
|
|
4227
5166
|
if (currentLeftTab === 'elements' || currentLeftTab === 'dom-tree') {
|
|
4228
5167
|
var treeRootId = currentLeftTab === 'elements' ? 'elements-root' : 'dom-tree-root';
|
|
@@ -4251,7 +5190,11 @@ function deselectElement(options) {
|
|
|
4251
5190
|
document.getElementById('rp-accordion').style.display = 'none';
|
|
4252
5191
|
document.getElementById('bc-path').textContent = 'No element selected';
|
|
4253
5192
|
document.getElementById('bc-path').style.color = 'var(--text-3)';
|
|
4254
|
-
|
|
5193
|
+
var preserveMainTab =
|
|
5194
|
+
!!(options && options.preserveMainTab) ||
|
|
5195
|
+
currentMainTab === 'history' ||
|
|
5196
|
+
currentMainTab === 'states';
|
|
5197
|
+
if (!preserveMainTab) switchMainTab('design');
|
|
4255
5198
|
if (!skipToolbarUpdate) updateSelectionToolbar();
|
|
4256
5199
|
syncDomTreeSelection();
|
|
4257
5200
|
} finally {
|
|
@@ -4338,6 +5281,30 @@ function setDragHandleActive(on) {
|
|
|
4338
5281
|
}
|
|
4339
5282
|
}
|
|
4340
5283
|
|
|
5284
|
+
function getIframeElementVisualRect(el) {
|
|
5285
|
+
var iframe = document.getElementById('iframeId');
|
|
5286
|
+
if (!el || !iframe) return null;
|
|
5287
|
+
// Element rects from the iframe document are in iframe viewport space, not the shell viewport.
|
|
5288
|
+
var elR = el.getBoundingClientRect();
|
|
5289
|
+
var iframeR = iframe.getBoundingClientRect();
|
|
5290
|
+
var cw = iframe.clientWidth || iframe.offsetWidth || 1;
|
|
5291
|
+
var ch = iframe.clientHeight || iframe.offsetHeight || 1;
|
|
5292
|
+
var scaleX = iframeR.width / cw;
|
|
5293
|
+
var scaleY = iframeR.height / ch;
|
|
5294
|
+
var top = iframeR.top + elR.top * scaleY;
|
|
5295
|
+
var left = iframeR.left + elR.left * scaleX;
|
|
5296
|
+
var width = elR.width * scaleX;
|
|
5297
|
+
var height = elR.height * scaleY;
|
|
5298
|
+
return {
|
|
5299
|
+
left: left,
|
|
5300
|
+
top: top,
|
|
5301
|
+
width: width,
|
|
5302
|
+
height: height,
|
|
5303
|
+
right: left + width,
|
|
5304
|
+
bottom: top + height,
|
|
5305
|
+
};
|
|
5306
|
+
}
|
|
5307
|
+
|
|
4341
5308
|
function positionSelectionToolbar() {
|
|
4342
5309
|
var bar = document.getElementById('selection-floater');
|
|
4343
5310
|
var iframe = document.getElementById('iframeId');
|
|
@@ -4349,16 +5316,20 @@ function positionSelectionToolbar() {
|
|
|
4349
5316
|
renderRightPanel(liveSelected);
|
|
4350
5317
|
syncDomTreeSelection();
|
|
4351
5318
|
}
|
|
4352
|
-
var elR = selectedEl
|
|
4353
|
-
|
|
5319
|
+
var elR = getIframeElementVisualRect(selectedEl);
|
|
5320
|
+
if (!elR) return;
|
|
4354
5321
|
var panelR = panel.getBoundingClientRect();
|
|
4355
|
-
var
|
|
4356
|
-
var
|
|
4357
|
-
|
|
4358
|
-
var
|
|
4359
|
-
|
|
5322
|
+
var panelScrollLeft = panel.scrollLeft || 0;
|
|
5323
|
+
var panelScrollTop = panel.scrollTop || 0;
|
|
5324
|
+
var left = elR.left - panelR.left + panelScrollLeft + elR.width / 2 - bar.offsetWidth / 2;
|
|
5325
|
+
var top = elR.top - panelR.top + panelScrollTop - bar.offsetHeight - 8;
|
|
5326
|
+
if (top < panelScrollTop + 6) top = elR.bottom - panelR.top + panelScrollTop + 8;
|
|
5327
|
+
var minL = panelScrollLeft + 6;
|
|
5328
|
+
var maxL = panelScrollLeft + Math.max(6, panel.clientWidth - bar.offsetWidth - 8);
|
|
5329
|
+
left = Math.max(minL, Math.min(left, maxL));
|
|
4360
5330
|
bar.style.left = Math.round(left) + 'px';
|
|
4361
5331
|
bar.style.top = Math.round(top) + 'px';
|
|
5332
|
+
syncMoveFloaterButtons(selectedEl);
|
|
4362
5333
|
}
|
|
4363
5334
|
|
|
4364
5335
|
function updateSelectionToolbar() {
|
|
@@ -4376,6 +5347,7 @@ function updateSelectionToolbar() {
|
|
|
4376
5347
|
if (selectedEl !== liveSelected) selectedEl = liveSelected;
|
|
4377
5348
|
selectedElFingerprint = buildSelector(liveSelected);
|
|
4378
5349
|
bar.style.display = 'flex';
|
|
5350
|
+
syncMoveFloaterButtons(liveSelected);
|
|
4379
5351
|
requestAnimationFrame(function() { positionSelectionToolbar(); });
|
|
4380
5352
|
}
|
|
4381
5353
|
|
|
@@ -4392,6 +5364,11 @@ function bindSelectionToolbarScroll() {
|
|
|
4392
5364
|
}
|
|
4393
5365
|
selectionScrollWin = w;
|
|
4394
5366
|
w.addEventListener('scroll', onFloaterScroll, true);
|
|
5367
|
+
var panel = document.getElementById('iframe-panel');
|
|
5368
|
+
if (panel && !selectionPanelScrollBound) {
|
|
5369
|
+
selectionPanelScrollBound = true;
|
|
5370
|
+
panel.addEventListener('scroll', onFloaterScroll, { passive: true });
|
|
5371
|
+
}
|
|
4395
5372
|
if (!selectionResizeBound) {
|
|
4396
5373
|
selectionResizeBound = true;
|
|
4397
5374
|
window.addEventListener('resize', onFloaterScroll);
|
|
@@ -4413,7 +5390,6 @@ function scrollIframeElementIntoView(el) {
|
|
|
4413
5390
|
function selectElementFromTree(el) {
|
|
4414
5391
|
selectElement(el);
|
|
4415
5392
|
scrollIframeElementIntoView(el);
|
|
4416
|
-
if (currentMainTab !== 'design') switchMainTab('design');
|
|
4417
5393
|
}
|
|
4418
5394
|
|
|
4419
5395
|
function duplicateSelectedEl() {
|
|
@@ -4486,12 +5462,26 @@ function toggleHideSelectedEl() {
|
|
|
4486
5462
|
|
|
4487
5463
|
function deleteSelectedEl() {
|
|
4488
5464
|
if (!selectedEl || !selectedEl.parentNode) return;
|
|
5465
|
+
var inst = selectedEl.getAttribute && selectedEl.getAttribute('data-vve-instance');
|
|
5466
|
+
if (inst && activeVarId && removeEditorInsertByInstanceId(inst)) {
|
|
5467
|
+
saveCurrentVariationHtml();
|
|
5468
|
+
recomputeEditorDirty();
|
|
5469
|
+
deselectElement();
|
|
5470
|
+
scheduleDomTreeRefresh();
|
|
5471
|
+
if (currentMainTab === 'history') renderHistoryTab();
|
|
5472
|
+
return;
|
|
5473
|
+
}
|
|
4489
5474
|
var delSel = buildSelector(selectedEl);
|
|
5475
|
+
var cancelledInsert =
|
|
5476
|
+
activeVarId && cancelSessionInsertForElement(activeVarId, selectedEl);
|
|
4490
5477
|
selectedEl.remove();
|
|
4491
|
-
if (activeVarId) {
|
|
5478
|
+
if (activeVarId && !cancelledInsert) {
|
|
4492
5479
|
var delRow = { selector: delSel, type: 'remove' };
|
|
4493
5480
|
appendSessionStructuralChainRow(activeVarId, delRow);
|
|
4494
5481
|
logStructuralStateChange(delRow, 'Deleted via toolbar', 'Element removed', null);
|
|
5482
|
+
} else if (cancelledInsert) {
|
|
5483
|
+
commitStateChangesForActiveVariation();
|
|
5484
|
+
if (currentMainTab === 'history') renderHistoryTab();
|
|
4495
5485
|
}
|
|
4496
5486
|
saveCurrentVariationHtml();
|
|
4497
5487
|
recomputeEditorDirty();
|
|
@@ -4517,35 +5507,190 @@ function syncDomTreeSelection() {
|
|
|
4517
5507
|
}
|
|
4518
5508
|
}
|
|
4519
5509
|
|
|
4520
|
-
function scheduleDomTreeRefresh() {
|
|
4521
|
-
if (
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
var
|
|
4526
|
-
|
|
4527
|
-
if (currentLeftTab === '
|
|
4528
|
-
|
|
4529
|
-
|
|
5510
|
+
function scheduleDomTreeRefresh() {
|
|
5511
|
+
if (domTreeRefreshTimer) clearTimeout(domTreeRefreshTimer);
|
|
5512
|
+
domTreeRefreshTimer = setTimeout(function() {
|
|
5513
|
+
domTreeRefreshTimer = null;
|
|
5514
|
+
var inp = document.getElementById('comp-search');
|
|
5515
|
+
var q = inp ? inp.value : '';
|
|
5516
|
+
renderElementsTree(q);
|
|
5517
|
+
if (currentLeftTab === 'dom-tree') renderDomTree(q);
|
|
5518
|
+
}, 150);
|
|
5519
|
+
}
|
|
5520
|
+
|
|
5521
|
+
function setDomTreeStatus(mode) {
|
|
5522
|
+
var root = document.getElementById('dom-tree-root');
|
|
5523
|
+
if (!root) return;
|
|
5524
|
+
if (mode === 'empty') {
|
|
5525
|
+
root.innerHTML = '<div class="dt-muted">Load a page to see the DOM tree.</div>';
|
|
5526
|
+
}
|
|
5527
|
+
}
|
|
5528
|
+
|
|
5529
|
+
function domTreePathSegment(el) {
|
|
5530
|
+
var tag = el.tagName.toLowerCase();
|
|
5531
|
+
var idx = 1;
|
|
5532
|
+
var s = el.previousElementSibling;
|
|
5533
|
+
while (s) {
|
|
5534
|
+
if (s.tagName === el.tagName) idx++;
|
|
5535
|
+
s = s.previousElementSibling;
|
|
5536
|
+
}
|
|
5537
|
+
return tag + '[' + idx + ']';
|
|
5538
|
+
}
|
|
5539
|
+
|
|
5540
|
+
function instanceIdFromInsertHtml(html) {
|
|
5541
|
+
var m = String(html || '').match(/data-vve-instance=["']([^"']+)["']/);
|
|
5542
|
+
return m ? m[1] : '';
|
|
5543
|
+
}
|
|
5544
|
+
|
|
5545
|
+
function resolveInsertedElementFromEntry(doc, entry) {
|
|
5546
|
+
if (!doc || !entry) return null;
|
|
5547
|
+
var instId = instanceIdFromInsertHtml(entry.html);
|
|
5548
|
+
if (!instId) return null;
|
|
5549
|
+
try {
|
|
5550
|
+
var safe = String(instId).split('"').join('\\"');
|
|
5551
|
+
return doc.querySelector('[data-vve-instance="' + safe + '"]');
|
|
5552
|
+
} catch(_) {
|
|
5553
|
+
return null;
|
|
5554
|
+
}
|
|
5555
|
+
}
|
|
5556
|
+
|
|
5557
|
+
function removeInsertFromDomByEntry(entry, iframeDoc) {
|
|
5558
|
+
if (!entry || !iframeDoc) return false;
|
|
5559
|
+
var insertedEl = resolveInsertedElementFromEntry(iframeDoc, entry);
|
|
5560
|
+
if (!insertedEl || !insertedEl.parentNode) return false;
|
|
5561
|
+
if (
|
|
5562
|
+
selectedEl &&
|
|
5563
|
+
(selectedEl === insertedEl || (insertedEl.contains && insertedEl.contains(selectedEl)))
|
|
5564
|
+
) {
|
|
5565
|
+
deselectElement();
|
|
5566
|
+
}
|
|
5567
|
+
insertedEl.remove();
|
|
5568
|
+
return true;
|
|
5569
|
+
}
|
|
5570
|
+
|
|
5571
|
+
/** Remove an editor insert everywhere (DOM + session + saved changesets + live history), keyed by data-vve-instance. */
|
|
5572
|
+
function removeEditorInsertByInstanceId(instId, opts) {
|
|
5573
|
+
if (!instId || !String(instId).trim()) return false;
|
|
5574
|
+
opts = opts || {};
|
|
5575
|
+
var varId = opts.varId || activeVarId;
|
|
5576
|
+
if (!varId) return false;
|
|
5577
|
+
var needle = 'data-vve-instance="' + String(instId).split('"').join('\\"') + '"';
|
|
5578
|
+
var didWork = false;
|
|
5579
|
+
|
|
5580
|
+
if (!opts.skipDom) {
|
|
5581
|
+
var iframeDoc = document.getElementById('iframeId').contentDocument;
|
|
5582
|
+
if (iframeDoc) {
|
|
5583
|
+
try {
|
|
5584
|
+
var safe = String(instId).split('"').join('\\"');
|
|
5585
|
+
var el = iframeDoc.querySelector('[data-vve-instance="' + safe + '"]');
|
|
5586
|
+
if (el && el.parentNode) {
|
|
5587
|
+
if (
|
|
5588
|
+
selectedEl &&
|
|
5589
|
+
(selectedEl === el || (el.contains && el.contains(selectedEl)))
|
|
5590
|
+
) {
|
|
5591
|
+
deselectElement();
|
|
5592
|
+
}
|
|
5593
|
+
el.remove();
|
|
5594
|
+
didWork = true;
|
|
5595
|
+
}
|
|
5596
|
+
} catch(_) {}
|
|
5597
|
+
}
|
|
5598
|
+
}
|
|
5599
|
+
|
|
5600
|
+
var sessionArr = sessionStructuralChainRowsByVarId[varId];
|
|
5601
|
+
if (sessionArr && sessionArr.length) {
|
|
5602
|
+
for (var i = sessionArr.length - 1; i >= 0; i--) {
|
|
5603
|
+
var row = sessionArr[i];
|
|
5604
|
+
if (!row || normalizeChangesetType(row) !== 'insert' || !row.html) continue;
|
|
5605
|
+
if (String(row.html).indexOf(needle) < 0) continue;
|
|
5606
|
+
var ts = row.vveTs;
|
|
5607
|
+
try {
|
|
5608
|
+
var k = structuralChangesetDedupKey(row);
|
|
5609
|
+
if (k) delete appliedStructuralChangesetKeys[k];
|
|
5610
|
+
} catch(_) {}
|
|
5611
|
+
sessionArr.splice(i, 1);
|
|
5612
|
+
removeStructuralStateChangeByTimestamp(varId, ts);
|
|
5613
|
+
didWork = true;
|
|
5614
|
+
}
|
|
5615
|
+
}
|
|
5616
|
+
|
|
5617
|
+
var v = variations.find(function(x) { return x._id === varId; });
|
|
5618
|
+
if (v) {
|
|
5619
|
+
var saved = parseVariationChangesets(v);
|
|
5620
|
+
var savedChanged = false;
|
|
5621
|
+
for (var si = saved.length - 1; si >= 0; si--) {
|
|
5622
|
+
var entry = saved[si];
|
|
5623
|
+
if (!entry || normalizeChangesetType(entry) !== 'insert' || !entry.html) continue;
|
|
5624
|
+
if (String(entry.html).indexOf(needle) < 0) continue;
|
|
5625
|
+
try {
|
|
5626
|
+
delete appliedChangesetSnapshots[entrySnapshotKey(entry)];
|
|
5627
|
+
} catch(_) {}
|
|
5628
|
+
saved.splice(si, 1);
|
|
5629
|
+
savedChanged = true;
|
|
5630
|
+
didWork = true;
|
|
5631
|
+
}
|
|
5632
|
+
if (savedChanged && varId === activeVarId) persistActiveVariationChangesets(saved);
|
|
5633
|
+
}
|
|
5634
|
+
|
|
5635
|
+
for (var j = stateChanges.length - 1; j >= 0; j--) {
|
|
5636
|
+
var c = stateChanges[j];
|
|
5637
|
+
if (!c || !c.isStructuralLive) continue;
|
|
5638
|
+
if (normalizeChangesetType({ type: c.structuralType }) !== 'insert') continue;
|
|
5639
|
+
var match = false;
|
|
5640
|
+
try {
|
|
5641
|
+
if (c.targetEl && c.targetEl.getAttribute && c.targetEl.getAttribute('data-vve-instance') === instId) {
|
|
5642
|
+
match = true;
|
|
5643
|
+
}
|
|
5644
|
+
} catch(_) {}
|
|
5645
|
+
if (match) {
|
|
5646
|
+
stateChanges.splice(j, 1);
|
|
5647
|
+
didWork = true;
|
|
5648
|
+
}
|
|
5649
|
+
}
|
|
5650
|
+
|
|
5651
|
+
return didWork;
|
|
4530
5652
|
}
|
|
4531
5653
|
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
if (!
|
|
4535
|
-
|
|
4536
|
-
|
|
5654
|
+
/** Live DOM nodes inserted via the visual editor, ordered by changeset/session insert order. */
|
|
5655
|
+
function collectEditorInsertedElements(doc) {
|
|
5656
|
+
if (!doc || !doc.body) return [];
|
|
5657
|
+
var byInst = {};
|
|
5658
|
+
var els;
|
|
5659
|
+
try {
|
|
5660
|
+
els = doc.querySelectorAll('[data-vve-instance]');
|
|
5661
|
+
} catch(_) {
|
|
5662
|
+
els = [];
|
|
5663
|
+
}
|
|
5664
|
+
for (var i = 0; i < els.length; i++) {
|
|
5665
|
+
var el = els[i];
|
|
5666
|
+
if (!el || el.nodeType !== 1) continue;
|
|
5667
|
+
var inst = el.getAttribute('data-vve-instance');
|
|
5668
|
+
if (inst && String(inst).trim()) byInst[String(inst)] = el;
|
|
4537
5669
|
}
|
|
4538
|
-
}
|
|
4539
5670
|
|
|
4540
|
-
|
|
4541
|
-
var
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
if (
|
|
4546
|
-
|
|
5671
|
+
var ordered = [];
|
|
5672
|
+
var seen = {};
|
|
5673
|
+
function addEl(el) {
|
|
5674
|
+
if (!el || !el.isConnected) return;
|
|
5675
|
+
var k = el.getAttribute && el.getAttribute('data-vve-instance');
|
|
5676
|
+
if (!k || seen[k]) return;
|
|
5677
|
+
seen[k] = true;
|
|
5678
|
+
ordered.push(el);
|
|
4547
5679
|
}
|
|
4548
|
-
|
|
5680
|
+
|
|
5681
|
+
if (activeVarId) {
|
|
5682
|
+
var variation = variations.find(function(v) { return v._id === activeVarId; });
|
|
5683
|
+
if (variation) {
|
|
5684
|
+
var cs = buildPersistedChainSetsForVariation(variation);
|
|
5685
|
+
for (var j = 0; j < cs.length; j++) {
|
|
5686
|
+
var row = cs[j];
|
|
5687
|
+
if (normalizeChangesetType(row) !== 'insert') continue;
|
|
5688
|
+
var instId = instanceIdFromInsertHtml(row.html);
|
|
5689
|
+
if (instId && byInst[instId]) addEl(byInst[instId]);
|
|
5690
|
+
}
|
|
5691
|
+
}
|
|
5692
|
+
}
|
|
5693
|
+
return ordered;
|
|
4549
5694
|
}
|
|
4550
5695
|
|
|
4551
5696
|
function renderElementsTree(filterRaw) {
|
|
@@ -4555,14 +5700,10 @@ function renderElementsTree(filterRaw) {
|
|
|
4555
5700
|
var iframe = document.getElementById('iframeId');
|
|
4556
5701
|
var doc = iframe && iframe.contentDocument;
|
|
4557
5702
|
if (!isIframeDomReady(iframe, doc)) {
|
|
4558
|
-
root.innerHTML = '<div class="dt-muted">Load a page to see
|
|
5703
|
+
root.innerHTML = '<div class="dt-muted">Load a page to see added elements.</div>';
|
|
4559
5704
|
return;
|
|
4560
5705
|
}
|
|
4561
5706
|
|
|
4562
|
-
function skippable(el) {
|
|
4563
|
-
return isDomTreeSkippableTagName(el.tagName);
|
|
4564
|
-
}
|
|
4565
|
-
|
|
4566
5707
|
function nodeIcon(tag) {
|
|
4567
5708
|
tag = (tag || '').toLowerCase();
|
|
4568
5709
|
if (/^h[1-6]$/.test(tag)) return 'bi bi-type-h1';
|
|
@@ -4582,50 +5723,10 @@ function renderElementsTree(filterRaw) {
|
|
|
4582
5723
|
return tag.toUpperCase();
|
|
4583
5724
|
}
|
|
4584
5725
|
|
|
4585
|
-
|
|
4586
|
-
if (!el || el.nodeType !== 1) return false;
|
|
4587
|
-
if (skippable(el)) return false;
|
|
4588
|
-
var tag = (el.tagName || '').toLowerCase();
|
|
4589
|
-
if (tag !== 'svg') {
|
|
4590
|
-
var p = el.parentElement;
|
|
4591
|
-
while (p) {
|
|
4592
|
-
if ((p.tagName || '').toLowerCase() === 'svg') return false;
|
|
4593
|
-
p = p.parentElement;
|
|
4594
|
-
}
|
|
4595
|
-
}
|
|
4596
|
-
return true;
|
|
4597
|
-
}
|
|
4598
|
-
|
|
4599
|
-
var nodes = [];
|
|
4600
|
-
var i, cursor;
|
|
4601
|
-
try {
|
|
4602
|
-
cursor = doc.createTreeWalker(doc.body, NodeFilter.SHOW_ELEMENT, null);
|
|
4603
|
-
} catch(_) {
|
|
4604
|
-
cursor = null;
|
|
4605
|
-
}
|
|
4606
|
-
if (cursor) {
|
|
4607
|
-
while (cursor.nextNode()) {
|
|
4608
|
-
var node = cursor.currentNode;
|
|
4609
|
-
if (isListableNode(node)) nodes.push(node);
|
|
4610
|
-
if (nodes.length > 4000) break;
|
|
4611
|
-
}
|
|
4612
|
-
} else {
|
|
4613
|
-
function collectFlat(el) {
|
|
4614
|
-
if (!el || !el.children) return;
|
|
4615
|
-
for (var j = 0; j < el.children.length; j++) {
|
|
4616
|
-
var c = el.children[j];
|
|
4617
|
-
if (!isListableNode(c)) continue;
|
|
4618
|
-
nodes.push(c);
|
|
4619
|
-
if (nodes.length > 4000) return;
|
|
4620
|
-
collectFlat(c);
|
|
4621
|
-
if (nodes.length > 4000) return;
|
|
4622
|
-
}
|
|
4623
|
-
}
|
|
4624
|
-
collectFlat(doc.body);
|
|
4625
|
-
}
|
|
5726
|
+
var nodes = collectEditorInsertedElements(doc);
|
|
4626
5727
|
|
|
4627
5728
|
root.innerHTML = '';
|
|
4628
|
-
for (i = 0; i < nodes.length; i++) {
|
|
5729
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
4629
5730
|
var el = nodes[i];
|
|
4630
5731
|
var lblText = labelFor(el);
|
|
4631
5732
|
if (filterText && lblText.toLowerCase().indexOf(filterText) < 0) continue;
|
|
@@ -4663,14 +5764,39 @@ function renderElementsTree(filterRaw) {
|
|
|
4663
5764
|
|
|
4664
5765
|
if (!root.querySelector('.dt-row')) {
|
|
4665
5766
|
root.innerHTML = filterText
|
|
4666
|
-
? '<div class="dt-muted">No elements match your search.</div>'
|
|
4667
|
-
: '<div class="dt-muted">No elements
|
|
5767
|
+
? '<div class="dt-muted">No added elements match your search.</div>'
|
|
5768
|
+
: '<div class="dt-muted">No elements added yet. Use Components or Sections to insert.</div>';
|
|
4668
5769
|
}
|
|
4669
5770
|
root.onmouseleave = function() {
|
|
4670
5771
|
clearTreeHoverHighlight();
|
|
4671
5772
|
};
|
|
4672
5773
|
}
|
|
4673
5774
|
|
|
5775
|
+
function domTreeLabelSuffix(el) {
|
|
5776
|
+
if (el.id != null && el.id !== '') return '#' + String(el.id).slice(0, 40);
|
|
5777
|
+
var cn = el.className && typeof el.className === 'string' ? el.className.trim() : '';
|
|
5778
|
+
if (cn) {
|
|
5779
|
+
var parts = cn.split(/s+/).filter(function(x) { return x.indexOf('vve-') !== 0; }).slice(0, 2).join('.');
|
|
5780
|
+
if (parts) return '.' + parts.slice(0, 56);
|
|
5781
|
+
}
|
|
5782
|
+
return '';
|
|
5783
|
+
}
|
|
5784
|
+
|
|
5785
|
+
function domTreeLabelFor(el) {
|
|
5786
|
+
return (el.tagName || '').toLowerCase() + domTreeLabelSuffix(el);
|
|
5787
|
+
}
|
|
5788
|
+
|
|
5789
|
+
function setDomTreeLabelContent(lbl, el) {
|
|
5790
|
+
var tag = (el.tagName || '').toLowerCase();
|
|
5791
|
+
lbl.textContent = '';
|
|
5792
|
+
var tagSpan = document.createElement('span');
|
|
5793
|
+
tagSpan.className = 'dt-tag';
|
|
5794
|
+
tagSpan.textContent = tag;
|
|
5795
|
+
lbl.appendChild(tagSpan);
|
|
5796
|
+
var suffix = domTreeLabelSuffix(el);
|
|
5797
|
+
if (suffix) lbl.appendChild(document.createTextNode(suffix));
|
|
5798
|
+
}
|
|
5799
|
+
|
|
4674
5800
|
function renderDomTree(filterRaw) {
|
|
4675
5801
|
var filterText = (filterRaw || '').toLowerCase().trim();
|
|
4676
5802
|
var root = document.getElementById('dom-tree-root');
|
|
@@ -4688,14 +5814,7 @@ function renderDomTree(filterRaw) {
|
|
|
4688
5814
|
}
|
|
4689
5815
|
|
|
4690
5816
|
function labelFor(el) {
|
|
4691
|
-
|
|
4692
|
-
if (el.id != null && el.id !== '') return tag + '#' + String(el.id).slice(0, 40);
|
|
4693
|
-
var cn = el.className && typeof el.className === 'string' ? el.className.trim() : '';
|
|
4694
|
-
if (cn) {
|
|
4695
|
-
var parts = cn.split(/s+/).filter(function(x) { return x.indexOf('vve-') !== 0; }).slice(0, 2).join('.');
|
|
4696
|
-
if (parts) return tag + '.' + parts.slice(0, 56);
|
|
4697
|
-
}
|
|
4698
|
-
return tag;
|
|
5817
|
+
return domTreeLabelFor(el);
|
|
4699
5818
|
}
|
|
4700
5819
|
|
|
4701
5820
|
function skippable(el) {
|
|
@@ -4772,7 +5891,7 @@ function renderDomTree(filterRaw) {
|
|
|
4772
5891
|
|
|
4773
5892
|
var lbl = document.createElement('div');
|
|
4774
5893
|
lbl.className = 'dt-lbl';
|
|
4775
|
-
lbl
|
|
5894
|
+
setDomTreeLabelContent(lbl, el);
|
|
4776
5895
|
lbl.title = buildSelector(el);
|
|
4777
5896
|
|
|
4778
5897
|
row.appendChild(chev);
|
|
@@ -4823,6 +5942,203 @@ function pr2(l1, i1, l2, i2) {
|
|
|
4823
5942
|
'<div class="pr2-item"><div class="pr2-lbl">'+l2+'</div>'+i2+'</div></div>';
|
|
4824
5943
|
}
|
|
4825
5944
|
function subLbl(text) { return '<div class="sub-lbl">'+text+'</div>'; }
|
|
5945
|
+
|
|
5946
|
+
function isLinkElement(el) {
|
|
5947
|
+
if (!el || el.nodeType !== 1) return false;
|
|
5948
|
+
var tag = (el.tagName || '').toLowerCase();
|
|
5949
|
+
if (tag === 'a') return true;
|
|
5950
|
+
try {
|
|
5951
|
+
return el.getAttribute && el.getAttribute('role') === 'link';
|
|
5952
|
+
} catch(_) {}
|
|
5953
|
+
return false;
|
|
5954
|
+
}
|
|
5955
|
+
|
|
5956
|
+
function isFormControlElement(el) {
|
|
5957
|
+
if (!el || el.nodeType !== 1) return false;
|
|
5958
|
+
var tag = (el.tagName || '').toLowerCase();
|
|
5959
|
+
return tag === 'input' || tag === 'textarea' || tag === 'select';
|
|
5960
|
+
}
|
|
5961
|
+
|
|
5962
|
+
function shouldShowInnerContentFields(el) {
|
|
5963
|
+
if (!el || el.nodeType !== 1) return false;
|
|
5964
|
+
var tag = (el.tagName || '').toLowerCase();
|
|
5965
|
+
if (tag === 'input' || tag === 'textarea' || tag === 'video') return false;
|
|
5966
|
+
if (isEmbeddedVideoIframe(el)) return false;
|
|
5967
|
+
return true;
|
|
5968
|
+
}
|
|
5969
|
+
|
|
5970
|
+
function elementHasHtmlChildren(el) {
|
|
5971
|
+
if (!el || el.nodeType !== 1) return false;
|
|
5972
|
+
try {
|
|
5973
|
+
var nodes = el.childNodes;
|
|
5974
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
5975
|
+
if (nodes[i].nodeType === 1) return true;
|
|
5976
|
+
}
|
|
5977
|
+
} catch(_) {}
|
|
5978
|
+
return false;
|
|
5979
|
+
}
|
|
5980
|
+
|
|
5981
|
+
function getFormControlValue(el) {
|
|
5982
|
+
if (!isFormControlElement(el)) return '';
|
|
5983
|
+
try {
|
|
5984
|
+
return el.value != null ? String(el.value) : '';
|
|
5985
|
+
} catch(_) {
|
|
5986
|
+
return '';
|
|
5987
|
+
}
|
|
5988
|
+
}
|
|
5989
|
+
|
|
5990
|
+
function getVideoSrc(el) {
|
|
5991
|
+
if (!el || el.nodeType !== 1) return '';
|
|
5992
|
+
try {
|
|
5993
|
+
var source = el.querySelector && el.querySelector('source');
|
|
5994
|
+
if (source && source.getAttribute('src')) return source.getAttribute('src') || '';
|
|
5995
|
+
return el.getAttribute('src') || '';
|
|
5996
|
+
} catch(_) {
|
|
5997
|
+
return '';
|
|
5998
|
+
}
|
|
5999
|
+
}
|
|
6000
|
+
|
|
6001
|
+
function setVideoSrc(el, value) {
|
|
6002
|
+
if (!el || el.nodeType !== 1) return;
|
|
6003
|
+
var v = value == null ? '' : String(value);
|
|
6004
|
+
try {
|
|
6005
|
+
var source = el.querySelector && el.querySelector('source');
|
|
6006
|
+
if (source) {
|
|
6007
|
+
if (v) source.setAttribute('src', v);
|
|
6008
|
+
else source.removeAttribute('src');
|
|
6009
|
+
} else if (v) {
|
|
6010
|
+
el.setAttribute('src', v);
|
|
6011
|
+
} else {
|
|
6012
|
+
el.removeAttribute('src');
|
|
6013
|
+
}
|
|
6014
|
+
try {
|
|
6015
|
+
el.load();
|
|
6016
|
+
} catch(_) {}
|
|
6017
|
+
} catch(_) {}
|
|
6018
|
+
}
|
|
6019
|
+
|
|
6020
|
+
function isYoutubeVideoElement(el) {
|
|
6021
|
+
if (!el || el.nodeType !== 1) return false;
|
|
6022
|
+
if ((el.tagName || '').toLowerCase() !== 'iframe') return false;
|
|
6023
|
+
if (el.hasAttribute && el.hasAttribute('data-youtube-id')) return true;
|
|
6024
|
+
var src = el.getAttribute('src') || '';
|
|
6025
|
+
return src.indexOf('youtube.com/embed/') !== -1 || src.indexOf('youtu.be/') !== -1;
|
|
6026
|
+
}
|
|
6027
|
+
|
|
6028
|
+
function normalizeYoutubeVideoId(input) {
|
|
6029
|
+
var raw = String(input || '').trim();
|
|
6030
|
+
if (!raw) return '';
|
|
6031
|
+
var m = raw.match(new RegExp('(?:youtube\\.com/(?:embed/|watch\\?(?:.*&)?v=|shorts/|live/)|youtu\\.be/)([A-Za-z0-9_-]{11})', 'i'));
|
|
6032
|
+
if (m) return m[1];
|
|
6033
|
+
var bare = raw.match(/^([A-Za-z0-9_-]{11})$/);
|
|
6034
|
+
return bare ? bare[1] : raw;
|
|
6035
|
+
}
|
|
6036
|
+
|
|
6037
|
+
function getYoutubeVideoId(el) {
|
|
6038
|
+
if (!isYoutubeVideoElement(el)) return '';
|
|
6039
|
+
try {
|
|
6040
|
+
var explicit = el.getAttribute('data-youtube-id');
|
|
6041
|
+
if (explicit != null && String(explicit).trim()) return String(explicit).trim();
|
|
6042
|
+
var src = el.getAttribute('src') || '';
|
|
6043
|
+
var m = src.match(new RegExp('(?:youtube\\.com/embed/|youtu\\.be/)([A-Za-z0-9_-]{11})', 'i'));
|
|
6044
|
+
return m ? m[1] : '';
|
|
6045
|
+
} catch(_) {
|
|
6046
|
+
return '';
|
|
6047
|
+
}
|
|
6048
|
+
}
|
|
6049
|
+
|
|
6050
|
+
function setYoutubeVideoId(el, value) {
|
|
6051
|
+
if (!el || el.nodeType !== 1) return;
|
|
6052
|
+
var id = normalizeYoutubeVideoId(value);
|
|
6053
|
+
try {
|
|
6054
|
+
if (id) {
|
|
6055
|
+
el.setAttribute('data-youtube-id', id);
|
|
6056
|
+
el.setAttribute('src', 'https://www.youtube.com/embed/' + id);
|
|
6057
|
+
} else {
|
|
6058
|
+
el.removeAttribute('data-youtube-id');
|
|
6059
|
+
el.setAttribute('src', 'about:blank');
|
|
6060
|
+
}
|
|
6061
|
+
} catch(_) {}
|
|
6062
|
+
}
|
|
6063
|
+
|
|
6064
|
+
function isVimeoVideoElement(el) {
|
|
6065
|
+
if (!el || el.nodeType !== 1) return false;
|
|
6066
|
+
if ((el.tagName || '').toLowerCase() !== 'iframe') return false;
|
|
6067
|
+
if (el.hasAttribute && el.hasAttribute('data-vimeo-id')) return true;
|
|
6068
|
+
var src = el.getAttribute('src') || '';
|
|
6069
|
+
return src.indexOf('player.vimeo.com/video/') !== -1 || src.indexOf('vimeo.com/video/') !== -1;
|
|
6070
|
+
}
|
|
6071
|
+
|
|
6072
|
+
function isEmbeddedVideoIframe(el) {
|
|
6073
|
+
return isYoutubeVideoElement(el) || isVimeoVideoElement(el);
|
|
6074
|
+
}
|
|
6075
|
+
|
|
6076
|
+
function normalizeVimeoVideoId(input) {
|
|
6077
|
+
var raw = String(input || '').trim();
|
|
6078
|
+
if (!raw) return '';
|
|
6079
|
+
var m = raw.match(new RegExp('(?:player\\.vimeo\\.com/video/|vimeo\\.com/(?:video/)?)([0-9]+)', 'i'));
|
|
6080
|
+
if (m) return m[1];
|
|
6081
|
+
var bare = raw.match(/^([0-9]+)$/);
|
|
6082
|
+
return bare ? bare[1] : raw.replace(/[^d]/g, '');
|
|
6083
|
+
}
|
|
6084
|
+
|
|
6085
|
+
function getVimeoVideoId(el) {
|
|
6086
|
+
if (!isVimeoVideoElement(el)) return '';
|
|
6087
|
+
try {
|
|
6088
|
+
var explicit = el.getAttribute('data-vimeo-id');
|
|
6089
|
+
if (explicit != null && String(explicit).trim()) return String(explicit).trim();
|
|
6090
|
+
var src = el.getAttribute('src') || '';
|
|
6091
|
+
var m = src.match(new RegExp('(?:player\\.vimeo\\.com/video/|vimeo\\.com/video/)([0-9]+)', 'i'));
|
|
6092
|
+
return m ? m[1] : '';
|
|
6093
|
+
} catch(_) {
|
|
6094
|
+
return '';
|
|
6095
|
+
}
|
|
6096
|
+
}
|
|
6097
|
+
|
|
6098
|
+
function setVimeoVideoId(el, value) {
|
|
6099
|
+
if (!el || el.nodeType !== 1) return;
|
|
6100
|
+
var id = normalizeVimeoVideoId(value);
|
|
6101
|
+
try {
|
|
6102
|
+
if (id) {
|
|
6103
|
+
el.setAttribute('data-vimeo-id', id);
|
|
6104
|
+
el.setAttribute('src', 'https://player.vimeo.com/video/' + id);
|
|
6105
|
+
} else {
|
|
6106
|
+
el.removeAttribute('data-vimeo-id');
|
|
6107
|
+
el.setAttribute('src', 'about:blank');
|
|
6108
|
+
}
|
|
6109
|
+
} catch(_) {}
|
|
6110
|
+
}
|
|
6111
|
+
|
|
6112
|
+
function buildAnchorContentFieldsHtml(el) {
|
|
6113
|
+
return (
|
|
6114
|
+
subLbl('Link attributes') +
|
|
6115
|
+
pr('Href', '<input class="pr-inp" id="pp-href" type="text" value="'+esc(el.getAttribute('href')||'')+'" placeholder="https:// or #section">') +
|
|
6116
|
+
pr2(
|
|
6117
|
+
'Target',
|
|
6118
|
+
'<select class="pr-inp" id="pp-target">'+selOpts(['','_self','_blank','_parent','_top'],el.getAttribute('target')||'')+'</select>',
|
|
6119
|
+
'Rel',
|
|
6120
|
+
'<input class="pr-inp" id="pp-rel" type="text" value="'+esc(el.getAttribute('rel')||'')+'" placeholder="noopener noreferrer">'
|
|
6121
|
+
) +
|
|
6122
|
+
pr('Title', '<input class="pr-inp" id="pp-link-title" type="text" value="'+esc(el.getAttribute('title')||'')+'">') +
|
|
6123
|
+
pr2(
|
|
6124
|
+
'Hreflang',
|
|
6125
|
+
'<input class="pr-inp" id="pp-hreflang" type="text" value="'+esc(el.getAttribute('hreflang')||'')+'" placeholder="en">',
|
|
6126
|
+
'Type',
|
|
6127
|
+
'<input class="pr-inp" id="pp-link-type" type="text" value="'+esc(el.getAttribute('type')||'')+'" placeholder="MIME type">'
|
|
6128
|
+
) +
|
|
6129
|
+
pr(
|
|
6130
|
+
'Referrer policy',
|
|
6131
|
+
'<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>'
|
|
6132
|
+
)
|
|
6133
|
+
);
|
|
6134
|
+
}
|
|
6135
|
+
|
|
6136
|
+
function setOptionalAnchorAttr(el, name, value) {
|
|
6137
|
+
if (!el || !name) return;
|
|
6138
|
+
var v = value == null ? '' : String(value).trim();
|
|
6139
|
+
if (v) el.setAttribute(name, v);
|
|
6140
|
+
else el.removeAttribute(name);
|
|
6141
|
+
}
|
|
4826
6142
|
function openCustomCssModal() {
|
|
4827
6143
|
var modal = document.getElementById('custom-css-modal');
|
|
4828
6144
|
var ta = document.getElementById('custom-css-modal-textarea');
|
|
@@ -5023,8 +6339,122 @@ function removeSizesEntry(i) {
|
|
|
5023
6339
|
}
|
|
5024
6340
|
}
|
|
5025
6341
|
|
|
6342
|
+
// \u2500\u2500 Video section state \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
6343
|
+
var _videoEl = null;
|
|
6344
|
+
|
|
6345
|
+
function renderVideoSection(el) {
|
|
6346
|
+
_videoEl = el;
|
|
6347
|
+
var sel = buildSelector(el);
|
|
6348
|
+
var src = getVideoSrc(el);
|
|
6349
|
+
var html = '';
|
|
6350
|
+
|
|
6351
|
+
if (src) {
|
|
6352
|
+
html += '<video class="video-preview" src="'+esc(src)+'" controls muted></video>';
|
|
6353
|
+
}
|
|
6354
|
+
|
|
6355
|
+
html += pr('Src', '<input class="pr-inp" id="pp-video-src" type="url" value="'+esc(src)+'" placeholder="https://example.com/video.mp4">');
|
|
6356
|
+
html += pr('Poster', '<input class="pr-inp" id="pp-video-poster" type="url" value="'+esc(el.getAttribute('poster')||'')+'" placeholder="https://\u2026">');
|
|
6357
|
+
|
|
6358
|
+
document.getElementById('acc-body-video').innerHTML = html;
|
|
6359
|
+
|
|
6360
|
+
var srcInp = document.getElementById('pp-video-src');
|
|
6361
|
+
if (srcInp) srcInp.addEventListener('input', function() {
|
|
6362
|
+
var orig = getOriginalValue('pp-video-src', el);
|
|
6363
|
+
setVideoSrc(el, srcInp.value);
|
|
6364
|
+
var prev = document.querySelector('.video-preview');
|
|
6365
|
+
if (prev) {
|
|
6366
|
+
prev.src = srcInp.value;
|
|
6367
|
+
prev.style.display = srcInp.value ? '' : 'none';
|
|
6368
|
+
} else if (srcInp.value) {
|
|
6369
|
+
renderVideoSection(el);
|
|
6370
|
+
}
|
|
6371
|
+
logChange(sel, 'pp-video-src', srcInp.value, el, orig);
|
|
6372
|
+
});
|
|
6373
|
+
var posterInp = document.getElementById('pp-video-poster');
|
|
6374
|
+
if (posterInp) posterInp.addEventListener('input', function() {
|
|
6375
|
+
var orig = el.getAttribute('poster') || '';
|
|
6376
|
+
if (posterInp.value) el.setAttribute('poster', posterInp.value);
|
|
6377
|
+
else el.removeAttribute('poster');
|
|
6378
|
+
var prev = document.querySelector('.video-preview');
|
|
6379
|
+
if (prev) prev.poster = posterInp.value;
|
|
6380
|
+
logChange(sel, 'pp-video-poster', posterInp.value, el, orig);
|
|
6381
|
+
});
|
|
6382
|
+
}
|
|
6383
|
+
|
|
6384
|
+
// \u2500\u2500 YouTube / Vimeo section state \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
6385
|
+
var _youtubeEl = null;
|
|
6386
|
+
var _vimeoEl = null;
|
|
6387
|
+
|
|
6388
|
+
function renderYoutubeSection(el) {
|
|
6389
|
+
_youtubeEl = el;
|
|
6390
|
+
var sel = buildSelector(el);
|
|
6391
|
+
var id = getYoutubeVideoId(el);
|
|
6392
|
+
var html = '';
|
|
6393
|
+
|
|
6394
|
+
if (id) {
|
|
6395
|
+
html += '<iframe class="embed-preview" src="https://www.youtube.com/embed/'+esc(id)+'" title="YouTube video preview" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>';
|
|
6396
|
+
}
|
|
6397
|
+
|
|
6398
|
+
html += pr('YouTube video ID', '<input class="pr-inp" id="pp-youtube-id" type="text" value="'+esc(id)+'" placeholder="dQw4w9WgXcQ">');
|
|
6399
|
+
|
|
6400
|
+
document.getElementById('acc-body-youtube').innerHTML = html;
|
|
6401
|
+
|
|
6402
|
+
var idInp = document.getElementById('pp-youtube-id');
|
|
6403
|
+
if (idInp) idInp.addEventListener('input', function() {
|
|
6404
|
+
var orig = getOriginalValue('pp-youtube-id', el);
|
|
6405
|
+
setYoutubeVideoId(el, idInp.value);
|
|
6406
|
+
var normalized = normalizeYoutubeVideoId(idInp.value);
|
|
6407
|
+
var prev = document.querySelector('#acc-body-youtube .embed-preview');
|
|
6408
|
+
if (prev) {
|
|
6409
|
+
if (normalized) {
|
|
6410
|
+
prev.src = 'https://www.youtube.com/embed/' + normalized;
|
|
6411
|
+
prev.style.display = '';
|
|
6412
|
+
} else {
|
|
6413
|
+
prev.style.display = 'none';
|
|
6414
|
+
}
|
|
6415
|
+
} else if (normalized) {
|
|
6416
|
+
renderYoutubeSection(el);
|
|
6417
|
+
}
|
|
6418
|
+
logChange(sel, 'pp-youtube-id', idInp.value, el, orig);
|
|
6419
|
+
});
|
|
6420
|
+
}
|
|
6421
|
+
|
|
6422
|
+
function renderVimeoSection(el) {
|
|
6423
|
+
_vimeoEl = el;
|
|
6424
|
+
var sel = buildSelector(el);
|
|
6425
|
+
var id = getVimeoVideoId(el);
|
|
6426
|
+
var html = '';
|
|
6427
|
+
|
|
6428
|
+
if (id) {
|
|
6429
|
+
html += '<iframe class="embed-preview" src="https://player.vimeo.com/video/'+esc(id)+'" title="Vimeo video preview" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe>';
|
|
6430
|
+
}
|
|
6431
|
+
|
|
6432
|
+
html += pr('Vimeo video ID', '<input class="pr-inp" id="pp-vimeo-id" type="text" value="'+esc(id)+'" placeholder="76979871">');
|
|
6433
|
+
|
|
6434
|
+
document.getElementById('acc-body-vimeo').innerHTML = html;
|
|
6435
|
+
|
|
6436
|
+
var idInp = document.getElementById('pp-vimeo-id');
|
|
6437
|
+
if (idInp) idInp.addEventListener('input', function() {
|
|
6438
|
+
var orig = getOriginalValue('pp-vimeo-id', el);
|
|
6439
|
+
setVimeoVideoId(el, idInp.value);
|
|
6440
|
+
var normalized = normalizeVimeoVideoId(idInp.value);
|
|
6441
|
+
var prev = document.querySelector('#acc-body-vimeo .embed-preview');
|
|
6442
|
+
if (prev) {
|
|
6443
|
+
if (normalized) {
|
|
6444
|
+
prev.src = 'https://player.vimeo.com/video/' + normalized;
|
|
6445
|
+
prev.style.display = '';
|
|
6446
|
+
} else {
|
|
6447
|
+
prev.style.display = 'none';
|
|
6448
|
+
}
|
|
6449
|
+
} else if (normalized) {
|
|
6450
|
+
renderVimeoSection(el);
|
|
6451
|
+
}
|
|
6452
|
+
logChange(sel, 'pp-vimeo-id', idInp.value, el, orig);
|
|
6453
|
+
});
|
|
6454
|
+
}
|
|
6455
|
+
|
|
5026
6456
|
// \u2500\u2500 Right panel rendering (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
|
|
5027
|
-
function renderRightPanel(el) {
|
|
6457
|
+
function renderRightPanel(el, options) {
|
|
5028
6458
|
if (!el) return;
|
|
5029
6459
|
var cs = el.ownerDocument.defaultView.getComputedStyle(el);
|
|
5030
6460
|
var tag = el.tagName.toLowerCase();
|
|
@@ -5035,20 +6465,54 @@ function renderRightPanel(el) {
|
|
|
5035
6465
|
document.getElementById('el-info').style.display = '';
|
|
5036
6466
|
document.getElementById('rp-accordion').style.display = '';
|
|
5037
6467
|
|
|
5038
|
-
// \u2500\u2500 Image
|
|
6468
|
+
// \u2500\u2500 Image / video accordions (show matching section at top) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5039
6469
|
var imgSec = document.getElementById('acc-image');
|
|
5040
6470
|
if (tag === 'img') {
|
|
5041
6471
|
imgSec.style.display = '';
|
|
5042
|
-
if (!imgSec.classList.contains('open')) imgSec.classList.add('open');
|
|
5043
6472
|
renderImageSection(el);
|
|
5044
6473
|
} else {
|
|
5045
6474
|
imgSec.style.display = 'none';
|
|
6475
|
+
imgSec.classList.remove('open');
|
|
5046
6476
|
_imageEl = null;
|
|
5047
6477
|
}
|
|
5048
6478
|
|
|
6479
|
+
var videoSec = document.getElementById('acc-video');
|
|
6480
|
+
if (tag === 'video') {
|
|
6481
|
+
videoSec.style.display = '';
|
|
6482
|
+
renderVideoSection(el);
|
|
6483
|
+
} else {
|
|
6484
|
+
videoSec.style.display = 'none';
|
|
6485
|
+
videoSec.classList.remove('open');
|
|
6486
|
+
_videoEl = null;
|
|
6487
|
+
}
|
|
6488
|
+
|
|
6489
|
+
var youtubeSec = document.getElementById('acc-youtube');
|
|
6490
|
+
if (isYoutubeVideoElement(el)) {
|
|
6491
|
+
youtubeSec.style.display = '';
|
|
6492
|
+
renderYoutubeSection(el);
|
|
6493
|
+
} else {
|
|
6494
|
+
youtubeSec.style.display = 'none';
|
|
6495
|
+
youtubeSec.classList.remove('open');
|
|
6496
|
+
_youtubeEl = null;
|
|
6497
|
+
}
|
|
6498
|
+
|
|
6499
|
+
var vimeoSec = document.getElementById('acc-vimeo');
|
|
6500
|
+
if (isVimeoVideoElement(el)) {
|
|
6501
|
+
vimeoSec.style.display = '';
|
|
6502
|
+
renderVimeoSection(el);
|
|
6503
|
+
} else {
|
|
6504
|
+
vimeoSec.style.display = 'none';
|
|
6505
|
+
vimeoSec.classList.remove('open');
|
|
6506
|
+
_vimeoEl = null;
|
|
6507
|
+
}
|
|
6508
|
+
|
|
6509
|
+
var activeAccSection =
|
|
6510
|
+
(options && options.preferredAccSection) ||
|
|
6511
|
+
getTypeDefaultAccSection(el);
|
|
6512
|
+
|
|
5049
6513
|
// \u2500\u2500 Typography \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5050
6514
|
document.getElementById('acc-body-typography').innerHTML =
|
|
5051
|
-
pr('Color', '<input type="color" class="pr-color" id="pp-color" value="'+esc(rgbToHex(cs.color))+'"><span style="font-size:11px;color:var(--text-3);flex:1;font-family:
|
|
6515
|
+
pr('Color', '<input type="color" class="pr-color" id="pp-color" value="'+esc(rgbToHex(cs.color))+'"><span style="font-size:11px;color:var(--text-3);flex:1;font-family:var(--font-mono)">'+esc(cs.color)+'</span>') +
|
|
5052
6516
|
pr2('Font size', '<input class="pr-inp" type="number" id="pp-fs" min="8" max="200" value="'+parseInt(cs.fontSize||'16')+'">',
|
|
5053
6517
|
'Font weight', '<select class="pr-inp" id="pp-fw">'+weightOpts(cs.fontWeight)+'</select>') +
|
|
5054
6518
|
pr('Font family', '<input class="pr-inp" id="pp-ff" type="text" value="'+esc(el.style.fontFamily||'')+'" placeholder="inherit">') +
|
|
@@ -5060,7 +6524,7 @@ function renderRightPanel(el) {
|
|
|
5060
6524
|
// \u2500\u2500 Background \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5061
6525
|
var bgiVal = (el.style.backgroundImage||'').replace(/url(['"]?([^'"]+)['"]?)/,'$1');
|
|
5062
6526
|
document.getElementById('acc-body-background').innerHTML =
|
|
5063
|
-
pr('Color', '<input type="color" class="pr-color" id="pp-bg" value="'+esc(rgbToHex(cs.backgroundColor))+'"><span style="font-size:11px;color:var(--text-3);flex:1;font-family:
|
|
6527
|
+
pr('Color', '<input type="color" class="pr-color" id="pp-bg" value="'+esc(rgbToHex(cs.backgroundColor))+'"><span style="font-size:11px;color:var(--text-3);flex:1;font-family:var(--font-mono)">'+esc(cs.backgroundColor)+'</span>') +
|
|
5064
6528
|
pr('Image URL', '<input class="pr-inp" id="pp-bgi" type="url" value="'+esc(bgiVal)+'" placeholder="https://\u2026">') +
|
|
5065
6529
|
pr2('Size', '<select class="pr-inp" id="pp-bgs">'+selOpts(['auto','cover','contain'],el.style.backgroundSize||'auto')+'</select>',
|
|
5066
6530
|
'Repeat', '<select class="pr-inp" id="pp-bgr">'+selOpts(['repeat','no-repeat','repeat-x','repeat-y'],el.style.backgroundRepeat||'repeat')+'</select>');
|
|
@@ -5130,9 +6594,9 @@ function renderRightPanel(el) {
|
|
|
5130
6594
|
// \u2500\u2500 Device styling rules \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5131
6595
|
document.getElementById('acc-body-device').innerHTML =
|
|
5132
6596
|
subLbl('Mobile (\u2264768px)') +
|
|
5133
|
-
'<textarea class="pr-inp" id="pp-mob-css" style="width:100%;min-height:60px;font-family:
|
|
6597
|
+
'<textarea class="pr-inp" id="pp-mob-css" style="width:100%;min-height:60px;font-family:var(--font-mono);font-size:11px;margin-bottom:8px" placeholder="/* styles for mobile */">'+esc(el.dataset.mobileCss||'')+'</textarea>' +
|
|
5134
6598
|
subLbl('Tablet (\u22641024px)') +
|
|
5135
|
-
'<textarea class="pr-inp" id="pp-tab-css" style="width:100%;min-height:60px;font-family:
|
|
6599
|
+
'<textarea class="pr-inp" id="pp-tab-css" style="width:100%;min-height:60px;font-family:var(--font-mono);font-size:11px" placeholder="/* styles for tablet */">'+esc(el.dataset.tabletCss||'')+'</textarea>';
|
|
5136
6600
|
|
|
5137
6601
|
// \u2500\u2500 CSS and Classes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5138
6602
|
document.getElementById('acc-body-css').innerHTML =
|
|
@@ -5143,27 +6607,41 @@ function renderRightPanel(el) {
|
|
|
5143
6607
|
'<i class="bi bi-fullscreen"></i>' +
|
|
5144
6608
|
'</button>' +
|
|
5145
6609
|
'</div>' +
|
|
5146
|
-
'<textarea class="pr-inp" id="pp-css" style="width:100%;min-height:80px;font-family:
|
|
6610
|
+
'<textarea class="pr-inp" id="pp-css" style="width:100%;min-height:80px;font-family:var(--font-mono);font-size:11px" placeholder="color: red; font-size: 16px;">'+esc(el.getAttribute('style')||'')+'</textarea>';
|
|
5147
6611
|
|
|
5148
6612
|
// \u2500\u2500 Attributes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5149
6613
|
var attrHtml =
|
|
5150
6614
|
pr('ID', '<input class="pr-inp" id="pp-id" type="text" value="'+esc(el.id||'')+'" placeholder="element-id">');
|
|
5151
|
-
if (tag==='a') attrHtml +=
|
|
5152
|
-
pr('Href', '<input class="pr-inp" id="pp-href" type="url" value="'+esc(el.getAttribute('href')||'')+'" placeholder="https://">') +
|
|
5153
|
-
pr('Target', '<select class="pr-inp" id="pp-target">'+selOpts(['','_blank','_self','_parent'],el.getAttribute('target')||'')+'</select>');
|
|
5154
6615
|
if (tag==='img') attrHtml +=
|
|
5155
6616
|
pr('Src', '<input class="pr-inp" id="pp-src" type="url" value="'+esc(el.getAttribute('src')||'')+'">') +
|
|
5156
6617
|
pr('Alt', '<input class="pr-inp" id="pp-alt" type="text" value="'+esc(el.getAttribute('alt')||'')+'">');
|
|
5157
|
-
if (tag==='input'||tag==='textarea') attrHtml +=
|
|
5158
|
-
pr('Placeholder', '<input class="pr-inp" id="pp-ph" type="text" value="'+esc(el.getAttribute('placeholder')||'')+'">');
|
|
5159
6618
|
document.getElementById('acc-body-attributes').innerHTML = attrHtml;
|
|
5160
6619
|
|
|
5161
6620
|
// \u2500\u2500 HTML Content \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
6621
|
+
var contentHtml = '';
|
|
6622
|
+
if (isLinkElement(el)) contentHtml += buildAnchorContentFieldsHtml(el);
|
|
6623
|
+
if (isFormControlElement(el)) {
|
|
6624
|
+
contentHtml +=
|
|
6625
|
+
subLbl('Value') +
|
|
6626
|
+
'<textarea class="pr-inp" id="pp-value" style="width:100%;min-height:44px;margin-bottom:8px">'+esc(getFormControlValue(el))+'</textarea>';
|
|
6627
|
+
}
|
|
6628
|
+
if (tag==='input' || tag==='textarea') {
|
|
6629
|
+
contentHtml +=
|
|
6630
|
+
subLbl('Placeholder') +
|
|
6631
|
+
'<input class="pr-inp" id="pp-ph" type="text" value="'+esc(el.getAttribute('placeholder')||'')+'" style="width:100%;margin-bottom:8px">';
|
|
6632
|
+
}
|
|
6633
|
+
if (shouldShowInnerContentFields(el)) {
|
|
6634
|
+
if (elementHasHtmlChildren(el)) {
|
|
6635
|
+
contentHtml +=
|
|
6636
|
+
subLbl('Inner HTML') +
|
|
6637
|
+
'<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>';
|
|
6638
|
+
} else {
|
|
6639
|
+
contentHtml +=
|
|
6640
|
+
subLbl('Inner Text') +
|
|
6641
|
+
'<textarea class="pr-inp" id="pp-text" style="width:100%;min-height:60px;margin-bottom:8px">'+esc(el.innerText||'')+'</textarea>';
|
|
6642
|
+
}
|
|
6643
|
+
}
|
|
6644
|
+
document.getElementById('acc-body-content').innerHTML = contentHtml;
|
|
5167
6645
|
|
|
5168
6646
|
// \u2500\u2500 Wire up all inputs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5169
6647
|
var bindings = [
|
|
@@ -5214,13 +6692,16 @@ function renderRightPanel(el) {
|
|
|
5214
6692
|
['pp-cls', function(v){el.className=v}],
|
|
5215
6693
|
['pp-css', function(v){el.setAttribute('style',v)}],
|
|
5216
6694
|
['pp-id', function(v){el.id=v}],
|
|
5217
|
-
['pp-href', function(v){el
|
|
5218
|
-
['pp-target', function(v){el
|
|
6695
|
+
['pp-href', function(v){setOptionalAnchorAttr(el,'href',v)}],
|
|
6696
|
+
['pp-target', function(v){setOptionalAnchorAttr(el,'target',v)}],
|
|
6697
|
+
['pp-rel', function(v){setOptionalAnchorAttr(el,'rel',v)}],
|
|
6698
|
+
['pp-link-title', function(v){setOptionalAnchorAttr(el,'title',v)}],
|
|
6699
|
+
['pp-hreflang', function(v){setOptionalAnchorAttr(el,'hreflang',v)}],
|
|
6700
|
+
['pp-link-type', function(v){setOptionalAnchorAttr(el,'type',v)}],
|
|
6701
|
+
['pp-referrerpolicy', function(v){setOptionalAnchorAttr(el,'referrerpolicy',v)}],
|
|
5219
6702
|
['pp-src', function(v){el.setAttribute('src',v)}],
|
|
5220
6703
|
['pp-alt', function(v){el.setAttribute('alt',v)}],
|
|
5221
6704
|
['pp-ph', function(v){el.setAttribute('placeholder',v)}],
|
|
5222
|
-
['pp-text', function(v){el.innerText=v}],
|
|
5223
|
-
['pp-html', function(v){el.innerHTML=v}],
|
|
5224
6705
|
];
|
|
5225
6706
|
var sel = buildSelector(el);
|
|
5226
6707
|
bindings.forEach(function(b){
|
|
@@ -5245,6 +6726,52 @@ function renderRightPanel(el) {
|
|
|
5245
6726
|
inp.addEventListener('change', onValueChange);
|
|
5246
6727
|
}
|
|
5247
6728
|
});
|
|
6729
|
+
wireContentFieldSync(el, sel);
|
|
6730
|
+
requestAnimationFrame(function() {
|
|
6731
|
+
requestAnimationFrame(function() {
|
|
6732
|
+
openAccSection(activeAccSection);
|
|
6733
|
+
});
|
|
6734
|
+
});
|
|
6735
|
+
}
|
|
6736
|
+
|
|
6737
|
+
function wireContentFieldSync(el, sel) {
|
|
6738
|
+
var textInp = document.getElementById('pp-text');
|
|
6739
|
+
var htmlInp = document.getElementById('pp-html');
|
|
6740
|
+
var valueInp = document.getElementById('pp-value');
|
|
6741
|
+
var syncing = false;
|
|
6742
|
+
function applyContentChange(changedId) {
|
|
6743
|
+
if (syncing) return;
|
|
6744
|
+
syncing = true;
|
|
6745
|
+
try {
|
|
6746
|
+
var orig = getOriginalValue(changedId, el);
|
|
6747
|
+
if (changedId === 'pp-value') {
|
|
6748
|
+
el.value = valueInp.value;
|
|
6749
|
+
logChange(sel, 'pp-value', valueInp.value, el, orig);
|
|
6750
|
+
} else if (changedId === 'pp-text') {
|
|
6751
|
+
el.innerText = textInp.value;
|
|
6752
|
+
if (htmlInp) htmlInp.value = el.innerHTML;
|
|
6753
|
+
logChange(sel, 'pp-text', textInp.value, el, orig);
|
|
6754
|
+
} else {
|
|
6755
|
+
el.innerHTML = htmlInp.value;
|
|
6756
|
+
if (textInp) textInp.value = el.innerText;
|
|
6757
|
+
logChange(sel, 'pp-html', htmlInp.value, el, orig);
|
|
6758
|
+
}
|
|
6759
|
+
} finally {
|
|
6760
|
+
syncing = false;
|
|
6761
|
+
}
|
|
6762
|
+
}
|
|
6763
|
+
if (valueInp && isFormControlElement(el)) {
|
|
6764
|
+
valueInp.addEventListener('input', function() { applyContentChange('pp-value'); });
|
|
6765
|
+
valueInp.addEventListener('change', function() { applyContentChange('pp-value'); });
|
|
6766
|
+
}
|
|
6767
|
+
if (textInp) {
|
|
6768
|
+
textInp.addEventListener('input', function() { applyContentChange('pp-text'); });
|
|
6769
|
+
textInp.addEventListener('change', function() { applyContentChange('pp-text'); });
|
|
6770
|
+
}
|
|
6771
|
+
if (htmlInp) {
|
|
6772
|
+
htmlInp.addEventListener('input', function() { applyContentChange('pp-html'); });
|
|
6773
|
+
htmlInp.addEventListener('change', function() { applyContentChange('pp-html'); });
|
|
6774
|
+
}
|
|
5248
6775
|
}
|
|
5249
6776
|
|
|
5250
6777
|
// \u2500\u2500 Selector helper \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
@@ -5465,6 +6992,100 @@ function repositionDragSibling(dragEl, clientY) {
|
|
|
5465
6992
|
}
|
|
5466
6993
|
}
|
|
5467
6994
|
|
|
6995
|
+
function isMoveSwapSkippableSibling(el) {
|
|
6996
|
+
if (!el || el.nodeType !== 1) return true;
|
|
6997
|
+
if (isDomTreeSkippableTagName(el.tagName)) return true;
|
|
6998
|
+
try {
|
|
6999
|
+
if (el.hasAttribute && el.hasAttribute('hidden')) return true;
|
|
7000
|
+
if (el.getAttribute && el.getAttribute('data-vve-hidden') === '1') return true;
|
|
7001
|
+
} catch(_) {}
|
|
7002
|
+
try {
|
|
7003
|
+
if (el.style && el.style.display === 'none') return true;
|
|
7004
|
+
if (el.style && el.style.visibility === 'hidden') return true;
|
|
7005
|
+
} catch(_) {}
|
|
7006
|
+
try {
|
|
7007
|
+
var view = el.ownerDocument && el.ownerDocument.defaultView;
|
|
7008
|
+
var cs = view && view.getComputedStyle ? view.getComputedStyle(el) : null;
|
|
7009
|
+
if (cs && (cs.display === 'none' || cs.visibility === 'hidden')) return true;
|
|
7010
|
+
} catch(_) {}
|
|
7011
|
+
return false;
|
|
7012
|
+
}
|
|
7013
|
+
|
|
7014
|
+
function findMoveSwapSibling(el, direction) {
|
|
7015
|
+
if (!el) return null;
|
|
7016
|
+
var node = direction < 0 ? el.previousElementSibling : el.nextElementSibling;
|
|
7017
|
+
while (node && isMoveSwapSkippableSibling(node)) {
|
|
7018
|
+
node = direction < 0 ? node.previousElementSibling : node.nextElementSibling;
|
|
7019
|
+
}
|
|
7020
|
+
return node;
|
|
7021
|
+
}
|
|
7022
|
+
|
|
7023
|
+
function isMoveParentEscapeBlocked(parent) {
|
|
7024
|
+
if (!parent || parent.nodeType !== 1) return true;
|
|
7025
|
+
var tag = (parent.tagName || '').toLowerCase();
|
|
7026
|
+
if (tag === 'html' || tag === 'body') return true;
|
|
7027
|
+
try {
|
|
7028
|
+
var doc = parent.ownerDocument;
|
|
7029
|
+
if (doc && (parent === doc.documentElement || parent === doc.body)) return true;
|
|
7030
|
+
} catch(_) {}
|
|
7031
|
+
return false;
|
|
7032
|
+
}
|
|
7033
|
+
|
|
7034
|
+
/** When no visual sibling exists, lift the node to the grandparent (before/after its parent). */
|
|
7035
|
+
function canMoveEscapeToParent(el, direction) {
|
|
7036
|
+
if (!el || !el.parentElement) return false;
|
|
7037
|
+
var parent = el.parentElement;
|
|
7038
|
+
if (isMoveParentEscapeBlocked(parent) || !parent.parentElement) return false;
|
|
7039
|
+
if (findMoveSwapSibling(el, direction)) return false;
|
|
7040
|
+
return true;
|
|
7041
|
+
}
|
|
7042
|
+
|
|
7043
|
+
function canMoveElDirection(el, direction) {
|
|
7044
|
+
if (!el || !el.parentElement) return false;
|
|
7045
|
+
return !!findMoveSwapSibling(el, direction) || canMoveEscapeToParent(el, direction);
|
|
7046
|
+
}
|
|
7047
|
+
|
|
7048
|
+
function moveElByDirection(el, direction) {
|
|
7049
|
+
if (!el || !el.parentElement) return false;
|
|
7050
|
+
var parent = el.parentElement;
|
|
7051
|
+
var sibling = findMoveSwapSibling(el, direction);
|
|
7052
|
+
if (sibling) {
|
|
7053
|
+
if (direction < 0) parent.insertBefore(el, sibling);
|
|
7054
|
+
else parent.insertBefore(sibling, el);
|
|
7055
|
+
return true;
|
|
7056
|
+
}
|
|
7057
|
+
if (!canMoveEscapeToParent(el, direction)) return false;
|
|
7058
|
+
var grandparent = parent.parentElement;
|
|
7059
|
+
if (!grandparent) return false;
|
|
7060
|
+
if (direction < 0) grandparent.insertBefore(el, parent);
|
|
7061
|
+
else grandparent.insertBefore(el, parent.nextSibling);
|
|
7062
|
+
return true;
|
|
7063
|
+
}
|
|
7064
|
+
|
|
7065
|
+
function syncMoveFloaterButtons(el) {
|
|
7066
|
+
var upBtn = document.getElementById('sf-move-up');
|
|
7067
|
+
var downBtn = document.getElementById('sf-move-down');
|
|
7068
|
+
if (!upBtn || !downBtn) return;
|
|
7069
|
+
var canUp = canMoveElDirection(el, -1);
|
|
7070
|
+
var canDown = canMoveElDirection(el, 1);
|
|
7071
|
+
upBtn.disabled = !canUp;
|
|
7072
|
+
downBtn.disabled = !canDown;
|
|
7073
|
+
if (canUp) {
|
|
7074
|
+
upBtn.title = findMoveSwapSibling(el, -1)
|
|
7075
|
+
? 'Move up'
|
|
7076
|
+
: 'Move up (out of container)';
|
|
7077
|
+
} else {
|
|
7078
|
+
upBtn.title = 'Cannot move up';
|
|
7079
|
+
}
|
|
7080
|
+
if (canDown) {
|
|
7081
|
+
downBtn.title = findMoveSwapSibling(el, 1)
|
|
7082
|
+
? 'Move down'
|
|
7083
|
+
: 'Move down (out of container)';
|
|
7084
|
+
} else {
|
|
7085
|
+
downBtn.title = 'Cannot move down';
|
|
7086
|
+
}
|
|
7087
|
+
}
|
|
7088
|
+
|
|
5468
7089
|
function recordReorderAfterDrag(movedEl) {
|
|
5469
7090
|
if (!activeVarId || !movedEl || !movedEl.parentElement) return;
|
|
5470
7091
|
var prev = movedEl.previousElementSibling;
|
|
@@ -5493,13 +7114,11 @@ function recordReorderAfterDrag(movedEl) {
|
|
|
5493
7114
|
}
|
|
5494
7115
|
|
|
5495
7116
|
function moveSelectedElByDirection(direction) {
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
if (!
|
|
5500
|
-
|
|
5501
|
-
else p.insertBefore(sibling, selectedEl);
|
|
5502
|
-
recordReorderAfterDrag(selectedEl);
|
|
7117
|
+
var el = recoverSelectedElement(false) || selectedEl;
|
|
7118
|
+
if (!el || !el.parentElement) return;
|
|
7119
|
+
selectedEl = el;
|
|
7120
|
+
if (!moveElByDirection(el, direction)) return;
|
|
7121
|
+
recordReorderAfterDrag(el);
|
|
5503
7122
|
saveCurrentVariationHtml();
|
|
5504
7123
|
recomputeEditorDirty();
|
|
5505
7124
|
scheduleDomTreeRefresh();
|
|
@@ -5599,6 +7218,7 @@ function attachClickHandler() {
|
|
|
5599
7218
|
deselectElement(); return;
|
|
5600
7219
|
}
|
|
5601
7220
|
selectElement(target);
|
|
7221
|
+
if (currentMainTab !== 'design') switchMainTab('design');
|
|
5602
7222
|
}, true);
|
|
5603
7223
|
} catch(_) {}
|
|
5604
7224
|
}
|
|
@@ -5703,15 +7323,18 @@ function syncIframeInteractions(reason) {
|
|
|
5703
7323
|
// \u2500\u2500 HTML insertion (Components / Sections) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5704
7324
|
/** Full snippets for Vvveb keys whose html field is placeholder text, not markup. */
|
|
5705
7325
|
var VVVEB_INSERT_HTML_OVERRIDES = {
|
|
5706
|
-
'html/gridrow': '<div
|
|
5707
|
-
'html/gridcolumn': '<div
|
|
5708
|
-
'html/container': '<div
|
|
5709
|
-
'html/btn-link': '<a
|
|
5710
|
-
'html/btn': '<button type="button"
|
|
5711
|
-
'html/
|
|
5712
|
-
'html/
|
|
5713
|
-
'html/
|
|
5714
|
-
'html/
|
|
7326
|
+
'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>',
|
|
7327
|
+
'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>',
|
|
7328
|
+
'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>',
|
|
7329
|
+
'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>',
|
|
7330
|
+
'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>',
|
|
7331
|
+
'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>',
|
|
7332
|
+
'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>',
|
|
7333
|
+
'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>',
|
|
7334
|
+
'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>',
|
|
7335
|
+
'html/breadcrumbitem': '<li style="display:inline;font-size:14px;color:#64748b"><a href="#" style="color:#2563eb;text-decoration:none">Item</a></li>',
|
|
7336
|
+
'html/listitem': '<li style="padding:10px 14px;font-size:14px;color:#334155;border:1px solid #e2e8f0;border-radius:6px;background:#fff">List item</li>',
|
|
7337
|
+
'html/tablebody': '<tbody><tr><td style="padding:10px 12px;border:1px solid #e2e8f0;font-size:14px">Cell</td></tr></tbody>',
|
|
5715
7338
|
};
|
|
5716
7339
|
|
|
5717
7340
|
function buildHtmlFromVvvebComponent(comp, typeKey) {
|
|
@@ -5739,7 +7362,7 @@ function insertVvvebComponent(typeKey) {
|
|
|
5739
7362
|
insertHtml(html);
|
|
5740
7363
|
}
|
|
5741
7364
|
|
|
5742
|
-
function insertHtml(html) {
|
|
7365
|
+
function insertHtml(html, options) {
|
|
5743
7366
|
if (!html) return;
|
|
5744
7367
|
try {
|
|
5745
7368
|
var iframe = document.getElementById('iframeId');
|
|
@@ -5767,7 +7390,18 @@ function insertHtml(html) {
|
|
|
5767
7390
|
} else {
|
|
5768
7391
|
doc.body.appendChild(frag);
|
|
5769
7392
|
}
|
|
5770
|
-
if (firstEl)
|
|
7393
|
+
if (firstEl) {
|
|
7394
|
+
try {
|
|
7395
|
+
firstEl.setAttribute('data-vve-instance', generateVveInstanceId());
|
|
7396
|
+
} catch(_) {}
|
|
7397
|
+
htmlStr = firstEl.outerHTML;
|
|
7398
|
+
}
|
|
7399
|
+
if (firstEl) {
|
|
7400
|
+
if (currentMainTab !== 'design') switchMainTab('design');
|
|
7401
|
+
selectElement(firstEl, {
|
|
7402
|
+
preferredAccSection: options && options.defaultAccSection,
|
|
7403
|
+
});
|
|
7404
|
+
}
|
|
5771
7405
|
if (activeVarId) {
|
|
5772
7406
|
var insertRow = {
|
|
5773
7407
|
selector: anchorSel,
|
|
@@ -5799,7 +7433,7 @@ function renderSidebar(filter) {
|
|
|
5799
7433
|
baseFiltered.forEach(function(c) {
|
|
5800
7434
|
var item = document.createElement('div'); item.className = 'cg-item'; item.title = 'Insert ' + c.name;
|
|
5801
7435
|
item.innerHTML = '<div class="cg-icon"><i class="bi ' + c.icon + '"></i></div><div class="cg-name">' + c.name + '</div>';
|
|
5802
|
-
item.onclick = function() { insertHtml(c.html); };
|
|
7436
|
+
item.onclick = function() { insertHtml(c.html, { defaultAccSection: c.defaultAccSection }); };
|
|
5803
7437
|
g1.appendChild(item);
|
|
5804
7438
|
});
|
|
5805
7439
|
compTab.appendChild(g1);
|
|
@@ -5839,8 +7473,10 @@ function renderSidebar(filter) {
|
|
|
5839
7473
|
var ch = document.createElement('div'); ch.className = 'cg-hdr'; ch.textContent = 'CRO Components'; secTab.appendChild(ch);
|
|
5840
7474
|
croFiltered.forEach(function(sec) {
|
|
5841
7475
|
var item = document.createElement('div'); item.className = 'sec-item';
|
|
5842
|
-
item.innerHTML = '<div class="sec-thumb">'+(sec
|
|
5843
|
-
item.onclick = function() {
|
|
7476
|
+
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>';
|
|
7477
|
+
item.onclick = function() {
|
|
7478
|
+
insertHtml(sec.html, { defaultAccSection: sec.defaultAccSection || 'content' });
|
|
7479
|
+
};
|
|
5844
7480
|
secTab.appendChild(item);
|
|
5845
7481
|
});
|
|
5846
7482
|
}
|
|
@@ -5853,7 +7489,9 @@ function renderSidebar(filter) {
|
|
|
5853
7489
|
if (!hasVv) { hasVv = true; var sh = document.createElement('div'); sh.className = 'cg-hdr'; sh.textContent = 'Bootstrap Sections'; secTab.appendChild(sh); }
|
|
5854
7490
|
var sel = document.createElement('div'); sel.className = 'sec-item';
|
|
5855
7491
|
sel.innerHTML = '<div class="sec-thumb">\u{1F4D0}</div><div class="sec-info"><div class="sec-name">'+snm+'</div></div>';
|
|
5856
|
-
sel.onclick = (function(s){ return function(){
|
|
7492
|
+
sel.onclick = (function(s){ return function(){
|
|
7493
|
+
insertHtml(s.html || '', { defaultAccSection: 'content' });
|
|
7494
|
+
}; })(sec);
|
|
5857
7495
|
secTab.appendChild(sel);
|
|
5858
7496
|
}
|
|
5859
7497
|
}
|
|
@@ -5869,11 +7507,7 @@ document.getElementById('comp-search').addEventListener('input', function() {
|
|
|
5869
7507
|
});
|
|
5870
7508
|
var btnAddElement = document.getElementById('btn-add-element');
|
|
5871
7509
|
if (btnAddElement) {
|
|
5872
|
-
btnAddElement.addEventListener('click',
|
|
5873
|
-
e.preventDefault();
|
|
5874
|
-
e.stopPropagation();
|
|
5875
|
-
toggleSectionComponentsPanel();
|
|
5876
|
-
});
|
|
7510
|
+
btnAddElement.addEventListener('click', handleAddElementClick);
|
|
5877
7511
|
}
|
|
5878
7512
|
|
|
5879
7513
|
// \u2500\u2500 Save / Close \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
@@ -6078,13 +7712,19 @@ function bindLoadingTooltipPositioning() {
|
|
|
6078
7712
|
// \u2500\u2500 Init \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
6079
7713
|
function registerCROSections() {
|
|
6080
7714
|
if (typeof Vvveb === 'undefined' || !Vvveb.Sections) return;
|
|
6081
|
-
CRO_SECTIONS.forEach(function(sec) {
|
|
7715
|
+
CRO_SECTIONS.forEach(function(sec) {
|
|
7716
|
+
Vvveb.Sections.add(sec.key, {
|
|
7717
|
+
name: sec.name,
|
|
7718
|
+
image: sec.image ? (CRO_SECTION_IMAGE_ROUTE + sec.image) : '',
|
|
7719
|
+
html: sec.html,
|
|
7720
|
+
});
|
|
7721
|
+
});
|
|
6082
7722
|
}
|
|
6083
7723
|
|
|
6084
7724
|
window.addEventListener('load', function() {
|
|
6085
7725
|
registerCROSections();
|
|
6086
7726
|
bindViewportControls();
|
|
6087
|
-
switchSectionComponentsTab(currentSectionComponentsTab);
|
|
7727
|
+
// switchSectionComponentsTab(currentSectionComponentsTab);
|
|
6088
7728
|
renderElementsTree(document.getElementById('comp-search').value);
|
|
6089
7729
|
vvvebReady = true;
|
|
6090
7730
|
bindLoadingTooltipPositioning();
|
|
@@ -6157,6 +7797,10 @@ window.addEventListener('load', function() {
|
|
|
6157
7797
|
syncIframeInteractions('iframe-load');
|
|
6158
7798
|
});
|
|
6159
7799
|
|
|
7800
|
+
var sfAdd = document.getElementById('sf-add');
|
|
7801
|
+
if (sfAdd) {
|
|
7802
|
+
sfAdd.addEventListener('click', handleAddElementClick);
|
|
7803
|
+
}
|
|
6160
7804
|
var sfMoveUp = document.getElementById('sf-move-up');
|
|
6161
7805
|
if (sfMoveUp) {
|
|
6162
7806
|
sfMoveUp.addEventListener('click', function(e) {
|
|
@@ -6256,6 +7900,20 @@ function createVisualEditorMiddleware(options) {
|
|
|
6256
7900
|
res.end(buildVvvebEditorHtml());
|
|
6257
7901
|
return;
|
|
6258
7902
|
}
|
|
7903
|
+
if (pathname.startsWith(CRO_SECTION_IMAGE_ROUTE)) {
|
|
7904
|
+
const filename = pathname.slice(CRO_SECTION_IMAGE_ROUTE.length);
|
|
7905
|
+
const filePath = resolveCroSectionImagePath(filename);
|
|
7906
|
+
if (!filePath) {
|
|
7907
|
+
res.statusCode = 404;
|
|
7908
|
+
res.end("Not found");
|
|
7909
|
+
return;
|
|
7910
|
+
}
|
|
7911
|
+
res.setHeader("Content-Type", "image/png");
|
|
7912
|
+
res.setHeader("Cache-Control", "public, max-age=86400");
|
|
7913
|
+
setFrameHeaders(req, res);
|
|
7914
|
+
res.end(fs__default.default.readFileSync(filePath));
|
|
7915
|
+
return;
|
|
7916
|
+
}
|
|
6259
7917
|
if (pathname === "/api/generate-test" && enableGenerateTestApi) {
|
|
6260
7918
|
if (req.method === "OPTIONS") {
|
|
6261
7919
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
@@ -6394,7 +8052,6 @@ function createVisualEditorMiddleware(options) {
|
|
|
6394
8052
|
const trackingMarkersForRequest = mergeTrackingMarkers(
|
|
6395
8053
|
extraTrackingMarkersForRequest
|
|
6396
8054
|
);
|
|
6397
|
-
console.log("trackingMarkersForRequest", trackingMarkersForRequest);
|
|
6398
8055
|
const strictFreezeParam = (url.searchParams.get("strictObserverFreeze") || "").toLowerCase();
|
|
6399
8056
|
const strictObserverFreezeForRequest = strictFreezeParam === "1" || strictFreezeParam === "true" || strictFreezeParam === "yes" ? true : strictFreezeParam === "0" || strictFreezeParam === "false" || strictFreezeParam === "no" ? false : strictObserverFreeze;
|
|
6400
8057
|
if (!targetUrl) {
|
|
@@ -7095,6 +8752,13 @@ function visualEditorProxyPlugin(options) {
|
|
|
7095
8752
|
generateBundle() {
|
|
7096
8753
|
this.emitFile({ type: "asset", fileName: "bridge.js", source: BRIDGE_SCRIPT });
|
|
7097
8754
|
this.emitFile({ type: "asset", fileName: "vvveb-editor/index.html", source: buildVvvebEditorHtml() });
|
|
8755
|
+
for (const imagePath of listCroSectionImageFiles()) {
|
|
8756
|
+
this.emitFile({
|
|
8757
|
+
type: "asset",
|
|
8758
|
+
fileName: path__default.default.join("images", "cro-sections", path__default.default.basename(imagePath)),
|
|
8759
|
+
source: fs__default.default.readFileSync(imagePath)
|
|
8760
|
+
});
|
|
8761
|
+
}
|
|
7098
8762
|
},
|
|
7099
8763
|
configureServer(server) {
|
|
7100
8764
|
server.middlewares.use(mw);
|