@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.js
CHANGED
|
@@ -3,6 +3,108 @@ import path from 'path';
|
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
|
|
5
5
|
// src/visualEditorProxyPlugin.ts
|
|
6
|
+
|
|
7
|
+
// src/croSections.ts
|
|
8
|
+
var CRO_SECTION_IMAGE_ROUTE = "/vvveb-editor-images/cro-sections/";
|
|
9
|
+
function croSectionImageFilename(key) {
|
|
10
|
+
return key.replace(/\//g, "-") + ".png";
|
|
11
|
+
}
|
|
12
|
+
var CRO_SECTIONS_BASE = [
|
|
13
|
+
{
|
|
14
|
+
key: "cro/hero",
|
|
15
|
+
name: "CRO Hero",
|
|
16
|
+
icon: "\u{1F3AF}",
|
|
17
|
+
desc: "High-converting hero section",
|
|
18
|
+
html: '<section style="background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);color:white;padding:80px 20px;text-align:center"><div style="max-width:700px;margin:0 auto"><h1 style="font-size:2.8rem;font-weight:800;margin-bottom:16px;color:white">Your Compelling Headline Here</h1><p style="font-size:1.15rem;margin-bottom:28px;opacity:0.9">A clear, benefit-focused subheadline that explains exactly what visitors get from you.</p><a href="#" style="display:inline-block;background:#f59e0b;color:white;padding:16px 40px;border-radius:6px;font-size:1.1rem;font-weight:700;text-decoration:none">Get Started Free →</a><p style="margin-top:14px;font-size:13px;opacity:0.65">✓ No credit card required · ✓ 14-day free trial</p></div></section>'
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
key: "cro/social-proof",
|
|
22
|
+
name: "Social Proof",
|
|
23
|
+
icon: "\u2B50",
|
|
24
|
+
desc: "Star rating + 3-column testimonials",
|
|
25
|
+
html: '<section style="padding:60px 20px;background:#f9fafb"><div style="max-width:1000px;margin:0 auto"><div style="text-align:center;margin-bottom:36px"><div style="font-size:2rem;color:#f59e0b;letter-spacing:4px">★★★★★</div><p style="font-weight:700;font-size:1.2rem;margin-top:4px">4.9 / 5 from 2,400+ verified reviews</p></div><div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:20px"><div style="background:white;border-radius:8px;padding:24px;box-shadow:0 1px 4px rgba(0,0,0,0.08)"><div style="color:#f59e0b;font-size:1.1rem;margin-bottom:10px">★★★★★</div><p style="font-size:14px;color:#444;margin-bottom:16px">"This product completely transformed our results. 40% increase in conversions within the first month."</p><div style="display:flex;align-items:center;gap:10px"><div style="width:36px;height:36px;border-radius:50%;background:#e0e7ff;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:14px">SJ</div><div><div style="font-weight:600;font-size:13px">Sarah Johnson</div><div style="font-size:11px;color:#888">VP Marketing, TechCorp</div></div></div></div><div style="background:white;border-radius:8px;padding:24px;box-shadow:0 1px 4px rgba(0,0,0,0.08)"><div style="color:#f59e0b;font-size:1.1rem;margin-bottom:10px">★★★★★</div><p style="font-size:14px;color:#444;margin-bottom:16px">"The ROI was immediate. Best investment we have made this year. Highly recommend to any serious marketer."</p><div style="display:flex;align-items:center;gap:10px"><div style="width:36px;height:36px;border-radius:50%;background:#dcfce7;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:14px">MC</div><div><div style="font-weight:600;font-size:13px">Mark Chen</div><div style="font-size:11px;color:#888">Founder, GrowthLabs</div></div></div></div><div style="background:white;border-radius:8px;padding:24px;box-shadow:0 1px 4px rgba(0,0,0,0.08)"><div style="color:#f59e0b;font-size:1.1rem;margin-bottom:10px">★★★★★</div><p style="font-size:14px;color:#444;margin-bottom:16px">"Incredible support and the product delivers exactly what it promises. Our entire team loves it."</p><div style="display:flex;align-items:center;gap:10px"><div style="width:36px;height:36px;border-radius:50%;background:#fee2e2;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:14px">AT</div><div><div style="font-weight:600;font-size:13px">Amanda Torres</div><div style="font-size:11px;color:#888">CMO, ScaleUp Inc</div></div></div></div></div></div></section>'
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
key: "cro/urgency-banner",
|
|
29
|
+
name: "Urgency Banner",
|
|
30
|
+
icon: "\u23F0",
|
|
31
|
+
desc: "Countdown timer + limited-time offer",
|
|
32
|
+
html: '<div style="background:#ef4444;color:white;text-align:center;padding:14px;font-size:14px;font-weight:500">🔥 Limited time offer: <strong>50% OFF</strong> ends in <span style="font-family:monospace;font-size:1rem;font-weight:700;background:rgba(0,0,0,0.2);padding:2px 10px;border-radius:4px;margin:0 6px">23:47:12</span>— <a href="#" style="color:white;font-weight:700;text-decoration:underline">Claim your discount →</a></div>'
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
key: "cro/trust-badges",
|
|
36
|
+
name: "Trust Badges",
|
|
37
|
+
icon: "\u{1F6E1}\uFE0F",
|
|
38
|
+
desc: "Security seals, payment icons, guarantees",
|
|
39
|
+
html: '<div style="padding:28px 20px;border-top:1px solid #e5e5e5;border-bottom:1px solid #e5e5e5;background:white"><div style="display:flex;flex-wrap:wrap;justify-content:center;align-items:center;gap:32px;max-width:700px;margin:0 auto"><div style="text-align:center;font-size:12px;color:#555"><div style="font-size:28px;margin-bottom:6px">🔒</div><div style="font-weight:600">SSL Secure</div><div style="font-size:10px;color:#888">256-bit encryption</div></div><div style="text-align:center;font-size:12px;color:#555"><div style="font-size:28px;margin-bottom:6px">↵</div><div style="font-weight:600">30-Day Guarantee</div><div style="font-size:10px;color:#888">Money back, no questions</div></div><div style="text-align:center;font-size:12px;color:#555"><div style="font-size:28px;margin-bottom:6px">⭐</div><div style="font-weight:600">4.9 / 5 Rating</div><div style="font-size:10px;color:#888">From 2,400+ reviews</div></div><div style="text-align:center;font-size:12px;color:#555"><div style="font-size:28px;margin-bottom:6px">💳</div><div style="font-weight:600">Secure Payment</div><div style="font-size:10px;color:#888">Visa · MC · PayPal</div></div></div></div>'
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
key: "cro/cta-block",
|
|
43
|
+
name: "CTA Block",
|
|
44
|
+
icon: "\u{1F4E3}",
|
|
45
|
+
desc: "Dark high-impact call-to-action section",
|
|
46
|
+
html: '<section style="background:#1a1a2e;color:white;padding:64px 20px;text-align:center"><div style="max-width:600px;margin:0 auto"><h2 style="font-size:2rem;font-weight:800;color:white;margin-bottom:10px">Ready to get started?</h2><p style="opacity:0.7;margin-bottom:32px">Join 10,000+ companies already seeing results with our platform.</p><div style="display:flex;gap:12px;justify-content:center;flex-wrap:wrap"><a href="#" style="display:inline-block;background:#f59e0b;color:white;padding:14px 36px;border-radius:6px;font-weight:700;text-decoration:none;font-size:1rem">Start Free Trial</a><a href="#" style="display:inline-block;border:2px solid rgba(255,255,255,0.4);color:white;padding:14px 36px;border-radius:6px;font-weight:600;text-decoration:none;font-size:1rem">Schedule Demo</a></div><p style="font-size:12px;margin-top:18px;opacity:0.45">No credit card required · Cancel anytime</p></div></section>'
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
key: "cro/feature-grid",
|
|
50
|
+
name: "Feature Grid",
|
|
51
|
+
icon: "\u2728",
|
|
52
|
+
desc: "3-column key benefits grid",
|
|
53
|
+
html: '<section style="padding:60px 20px;background:white"><div style="max-width:900px;margin:0 auto"><h2 style="text-align:center;font-size:1.8rem;font-weight:800;margin-bottom:48px">Why choose us?</h2><div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:32px;text-align:center"><div><div style="font-size:2.5rem;margin-bottom:14px">🚀</div><h5 style="font-weight:700;margin-bottom:8px">Fast Results</h5><p style="color:#666;font-size:14px">See improvements in your conversion rate within the first 30 days or your money back.</p></div><div><div style="font-size:2.5rem;margin-bottom:14px">📊</div><h5 style="font-weight:700;margin-bottom:8px">Data-Driven</h5><p style="color:#666;font-size:14px">Every decision backed by real user data and statistical significance testing.</p></div><div><div style="font-size:2.5rem;margin-bottom:14px">🎯</div><h5 style="font-weight:700;margin-bottom:8px">Precision Targeting</h5><p style="color:#666;font-size:14px">Target the right audience segments with personalized, high-converting experiences.</p></div></div></div></section>'
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
key: "cro/exit-intent-bar",
|
|
57
|
+
name: "Exit Intent Bar",
|
|
58
|
+
icon: "\u{1F6AA}",
|
|
59
|
+
desc: "Sticky bottom bar for exit-intent capture",
|
|
60
|
+
html: `<div style="position:fixed;bottom:0;left:0;right:0;background:#1e293b;color:white;padding:14px 20px;display:flex;align-items:center;justify-content:center;gap:16px;z-index:9999;box-shadow:0 -4px 20px rgba(0,0,0,0.2)"><span style="font-size:14px">🔔 <strong>Wait!</strong> Don't leave empty-handed — get 20% off your first order.</span><a href="#" style="background:#f59e0b;color:white;padding:8px 20px;border-radius:4px;font-weight:700;text-decoration:none;font-size:13px;white-space:nowrap">Claim Offer</a><a href="#" style="color:rgba(255,255,255,0.5);font-size:12px;text-decoration:none">No thanks</a></div>`
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
key: "cro/pricing-table",
|
|
64
|
+
name: "Pricing Table",
|
|
65
|
+
icon: "\u{1F4B0}",
|
|
66
|
+
desc: "3-tier pricing with highlighted plan",
|
|
67
|
+
html: '<section style="padding:60px 20px;background:#f8fafc"><div style="max-width:900px;margin:0 auto"><h2 style="text-align:center;font-weight:800;font-size:1.8rem;margin-bottom:8px">Simple, transparent pricing</h2><p style="text-align:center;color:#666;margin-bottom:48px">No hidden fees. Cancel anytime.</p><div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:20px"><div style="background:white;border:1px solid #e5e5e5;border-radius:10px;padding:28px"><h3 style="font-weight:700;margin-bottom:6px">Starter</h3><div style="font-size:2rem;font-weight:800;margin-bottom:16px">$29<span style="font-size:1rem;font-weight:400;color:#888">/mo</span></div><ul style="list-style:none;padding:0;font-size:14px;color:#555;margin-bottom:24px"><li style="padding:6px 0;border-bottom:1px solid #f0f0f0">✓ Up to 10,000 visitors/mo</li><li style="padding:6px 0;border-bottom:1px solid #f0f0f0">✓ 5 A/B tests</li><li style="padding:6px 0">✓ Email support</li></ul><a href="#" style="display:block;text-align:center;border:2px solid #e5e5e5;padding:10px;border-radius:6px;font-weight:600;text-decoration:none;color:#333">Get started</a></div><div style="background:#3b82f6;border-radius:10px;padding:28px;position:relative;transform:scale(1.04);box-shadow:0 8px 32px rgba(59,130,246,0.3)"><div style="position:absolute;top:-12px;left:50%;transform:translateX(-50%);background:#f59e0b;color:white;font-size:11px;font-weight:700;padding:4px 12px;border-radius:20px">MOST POPULAR</div><h3 style="font-weight:700;margin-bottom:6px;color:white">Pro</h3><div style="font-size:2rem;font-weight:800;margin-bottom:16px;color:white">$79<span style="font-size:1rem;font-weight:400;opacity:0.7">/mo</span></div><ul style="list-style:none;padding:0;font-size:14px;color:rgba(255,255,255,0.85);margin-bottom:24px"><li style="padding:6px 0;border-bottom:1px solid rgba(255,255,255,0.15)">✓ Up to 100,000 visitors/mo</li><li style="padding:6px 0;border-bottom:1px solid rgba(255,255,255,0.15)">✓ Unlimited A/B tests</li><li style="padding:6px 0">✓ Priority support</li></ul><a href="#" style="display:block;text-align:center;background:white;color:#3b82f6;padding:10px;border-radius:6px;font-weight:700;text-decoration:none">Get started</a></div><div style="background:white;border:1px solid #e5e5e5;border-radius:10px;padding:28px"><h3 style="font-weight:700;margin-bottom:6px">Enterprise</h3><div style="font-size:2rem;font-weight:800;margin-bottom:16px">Custom</div><ul style="list-style:none;padding:0;font-size:14px;color:#555;margin-bottom:24px"><li style="padding:6px 0;border-bottom:1px solid #f0f0f0">✓ Unlimited visitors</li><li style="padding:6px 0;border-bottom:1px solid #f0f0f0">✓ White-label option</li><li style="padding:6px 0">✓ Dedicated support</li></ul><a href="#" style="display:block;text-align:center;border:2px solid #e5e5e5;padding:10px;border-radius:6px;font-weight:600;text-decoration:none;color:#333">Contact sales</a></div></div></div></section>'
|
|
68
|
+
}
|
|
69
|
+
];
|
|
70
|
+
var CRO_SECTIONS = CRO_SECTIONS_BASE.map((section) => ({
|
|
71
|
+
...section,
|
|
72
|
+
image: croSectionImageFilename(section.key)
|
|
73
|
+
}));
|
|
74
|
+
|
|
75
|
+
// src/visualEditorProxyPlugin.ts
|
|
76
|
+
var PACKAGE_ROOT = path.dirname(fileURLToPath(import.meta.url));
|
|
77
|
+
function resolveCroSectionImagePath(filename) {
|
|
78
|
+
const safe = path.basename(filename);
|
|
79
|
+
if (!safe || safe !== filename) return null;
|
|
80
|
+
const candidates = [
|
|
81
|
+
path.join(PACKAGE_ROOT, "images", "cro-sections", safe),
|
|
82
|
+
path.join(PACKAGE_ROOT, "..", "src", "images", "cro-sections", safe),
|
|
83
|
+
path.join(process.cwd(), "src", "images", "cro-sections", safe)
|
|
84
|
+
];
|
|
85
|
+
for (const candidate of candidates) {
|
|
86
|
+
try {
|
|
87
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
88
|
+
} catch (_) {
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
function listCroSectionImageFiles() {
|
|
94
|
+
const dirs = [
|
|
95
|
+
path.join(PACKAGE_ROOT, "images", "cro-sections"),
|
|
96
|
+
path.join(PACKAGE_ROOT, "..", "src", "images", "cro-sections"),
|
|
97
|
+
path.join(process.cwd(), "src", "images", "cro-sections")
|
|
98
|
+
];
|
|
99
|
+
for (const dir of dirs) {
|
|
100
|
+
try {
|
|
101
|
+
if (!fs.existsSync(dir)) continue;
|
|
102
|
+
return fs.readdirSync(dir).filter((name) => name.endsWith(".png")).map((name) => path.join(dir, name));
|
|
103
|
+
} catch (_) {
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return [];
|
|
107
|
+
}
|
|
6
108
|
var DEFAULT_TRACKING_MARKERS = [
|
|
7
109
|
"snowplow",
|
|
8
110
|
"taboola",
|
|
@@ -254,64 +356,6 @@ catch(_){}})();</script>`;
|
|
|
254
356
|
var AI_SYSTEM_PROMPT = `You are a CRO expert. Return JSON only with: hypothesis, mutations, summary. Keep 2-6 precise mutations and only valid selectors from snapshot.`;
|
|
255
357
|
var BRIDGE_SCRIPT = `(function(){if(window.__CONVERSION_BRIDGE_LOADED__)return;window.__CONVERSION_BRIDGE_LOADED__=true;var CHANNEL='conversion-editor';var highlightEl=null;function send(payload){window.parent.postMessage({channel:CHANNEL,payload:payload},'*');}function qs(selector){try{return document.querySelector(selector);}catch(_){return null;}}function getSelector(el){if(!el||el.nodeType!==1)return'';if(el.id)return'#'+CSS.escape(el.id);var parts=[];var current=el;var depth=0;while(current&¤t.nodeType===1&&depth<5){var part=current.tagName.toLowerCase();if(current.classList&¤t.classList.length){part+='.'+Array.from(current.classList).slice(0,2).map(function(c){return CSS.escape(c);}).join('.');}var parent=current.parentElement;if(parent){var siblings=Array.from(parent.children).filter(function(s){return s.tagName===current.tagName;});if(siblings.length>1)part+=':nth-of-type('+(siblings.indexOf(current)+1)+')';}parts.unshift(part);current=parent;depth+=1;}return parts.join(' > ');}function payloadOf(el){var rect=el.getBoundingClientRect();var style=window.getComputedStyle(el);return{selector:getSelector(el),tagName:el.tagName.toLowerCase(),textContent:(el.textContent||'').trim().slice(0,500),computedStyles:{color:style.color,backgroundColor:style.backgroundColor,fontSize:style.fontSize,fontWeight:style.fontWeight,lineHeight:style.lineHeight,display:style.display},rect:{top:rect.top,left:rect.left,width:rect.width,height:rect.height}};}function applyMutation(m){var el=qs(m.selector);if(!el)return;switch(m.action){case'setStyle':if(m.property)el.style[m.property]=m.value;break;case'setText':el.textContent=m.value;break;case'setHTML':el.innerHTML=m.value;break;case'setAttribute':if(m.property)el.setAttribute(m.property,m.value);break;case'hide':el.style.display='none';break;case'show':el.style.display='';break;case'insertHTML':if(m.position)el.insertAdjacentHTML(m.position,m.value||'');break;case'insertSection':if(m.position)el.insertAdjacentHTML(m.position,m.sectionHtml||m.value||'');break;case'reorderElement':if(!m.targetSelector)break;var target=qs(m.targetSelector);if(!target||!target.parentNode||!el.parentNode)break;if(m.insertPosition==='before')target.parentNode.insertBefore(el,target);else target.parentNode.insertBefore(el,target.nextSibling);break;default:break;}}function revertMutation(m){var el=qs(m.selector);if(!el)return;switch(m.action){case'setStyle':if(m.property)el.style[m.property]=m.previous||'';break;case'setText':el.textContent=m.previous||'';break;case'setHTML':el.innerHTML=m.previous||'';break;case'setAttribute':if(m.property){if(m.previous!=null)el.setAttribute(m.property,m.previous);else el.removeAttribute(m.property);}break;case'hide':case'show':el.style.display=m.previous||'';break;default:break;}}function captureSnapshot(){var elements=Array.from(document.querySelectorAll('h1,h2,h3,p,button,a,input,select,img,section,div')).slice(0,700).map(function(el){var rect=el.getBoundingClientRect();var cs=window.getComputedStyle(el);return{selector:getSelector(el),parentSelector:el.parentElement?getSelector(el.parentElement):null,tagName:el.tagName.toLowerCase(),textContent:(el.textContent||'').trim().slice(0,300),attributes:Array.from(el.attributes||[]).reduce(function(acc,a){acc[a.name]=a.value;return acc;},{}),computedStyles:{color:cs.color,backgroundColor:cs.backgroundColor,fontSize:cs.fontSize,fontWeight:cs.fontWeight,display:cs.display},childrenCount:el.children?el.children.length:0,aboveFold:rect.top<window.innerHeight,depth:(function(){var d=0,p=el.parentElement;while(p&&d<25){d++;p=p.parentElement;}return d;})()};});send({type:'snapshotCaptured',snapshot:{url:window.location.href,title:document.title,viewport:{width:window.innerWidth,height:window.innerHeight},elements:elements}});}function captureTree(){function toNode(el,depth){var rect=el.getBoundingClientRect();var tag=el.tagName.toLowerCase();var type='generic';if(tag==='section')type='section';else if(tag==='img')type='image';else if(tag==='a')type='link';else if(tag==='button')type='button';else if(tag==='form')type='form';else if(['p','h1','h2','h3','h4','h5','h6','span'].indexOf(tag)>=0)type='text';else if(['div','main','article','aside','header','footer','nav'].indexOf(tag)>=0)type='container';var children=Array.from(el.children||[]).slice(0,50).map(function(c){return toNode(c,depth+1);});return{id:getSelector(el),selector:getSelector(el),tagName:tag,label:(el.getAttribute('aria-label')||el.getAttribute('id')||el.className||tag).toString().slice(0,80),type:type,children:children,depth:depth,isAboveFold:rect.top<window.innerHeight,rect:{top:rect.top,left:rect.left,width:rect.width,height:rect.height}};}send({type:'pageTreeCaptured',tree:[toNode(document.body,0)]});}window.addEventListener('message',function(e){var msg=e.data;if(!msg||msg.channel!==CHANNEL||!msg.payload)return;var p=msg.payload;switch(p.type){case'ping':send({type:'pong'});break;case'applyMutation':applyMutation(p.mutation);break;case'applyMutationBatch':(p.mutations||[]).forEach(applyMutation);break;case'revert':revertMutation(p.mutation);break;case'clearAllMutations':window.location.reload();break;case'captureSnapshot':captureSnapshot();break;case'validateSelectors':send({type:'selectorsValidated',results:(p.selectors||[]).map(function(s){var el=qs(s);return{selector:s,found:!!el,tagName:el?el.tagName.toLowerCase():null};})});break;case'scrollToElement':case'selectElement':var target=qs(p.selector);if(target){target.scrollIntoView({behavior:'smooth',block:'center'});send({type:'elementSelected',element:payloadOf(target)});}break;case'hoverElement':var h=qs(p.selector);if(h){if(highlightEl)highlightEl.style.outline='';h.style.outline='2px solid #3b82f6';highlightEl=h;}break;case'capturePageTree':captureTree();break;default:break;}});document.addEventListener('click',function(e){var el=e.target;if(!(el instanceof Element))return;send({type:'elementSelected',element:payloadOf(el)});},true);send({type:'bridgeReady'});})();`;
|
|
256
358
|
function buildVvvebEditorHtml() {
|
|
257
|
-
const CRO_SECTIONS = [
|
|
258
|
-
{
|
|
259
|
-
key: "cro/hero",
|
|
260
|
-
name: "CRO Hero",
|
|
261
|
-
icon: "\u{1F3AF}",
|
|
262
|
-
desc: "High-converting hero section",
|
|
263
|
-
html: '<section style="background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);color:white;padding:80px 20px;text-align:center"><div style="max-width:700px;margin:0 auto"><h1 style="font-size:2.8rem;font-weight:800;margin-bottom:16px;color:white">Your Compelling Headline Here</h1><p style="font-size:1.15rem;margin-bottom:28px;opacity:0.9">A clear, benefit-focused subheadline that explains exactly what visitors get from you.</p><a href="#" style="display:inline-block;background:#f59e0b;color:white;padding:16px 40px;border-radius:6px;font-size:1.1rem;font-weight:700;text-decoration:none">Get Started Free →</a><p style="margin-top:14px;font-size:13px;opacity:0.65">✓ No credit card required · ✓ 14-day free trial</p></div></section>'
|
|
264
|
-
},
|
|
265
|
-
{
|
|
266
|
-
key: "cro/social-proof",
|
|
267
|
-
name: "Social Proof",
|
|
268
|
-
icon: "\u2B50",
|
|
269
|
-
desc: "Star rating + 3-column testimonials",
|
|
270
|
-
html: '<section style="padding:60px 20px;background:#f9fafb"><div style="max-width:1000px;margin:0 auto"><div style="text-align:center;margin-bottom:36px"><div style="font-size:2rem;color:#f59e0b;letter-spacing:4px">★★★★★</div><p style="font-weight:700;font-size:1.2rem;margin-top:4px">4.9 / 5 from 2,400+ verified reviews</p></div><div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:20px"><div style="background:white;border-radius:8px;padding:24px;box-shadow:0 1px 4px rgba(0,0,0,0.08)"><div style="color:#f59e0b;font-size:1.1rem;margin-bottom:10px">★★★★★</div><p style="font-size:14px;color:#444;margin-bottom:16px">"This product completely transformed our results. 40% increase in conversions within the first month."</p><div style="display:flex;align-items:center;gap:10px"><div style="width:36px;height:36px;border-radius:50%;background:#e0e7ff;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:14px">SJ</div><div><div style="font-weight:600;font-size:13px">Sarah Johnson</div><div style="font-size:11px;color:#888">VP Marketing, TechCorp</div></div></div></div><div style="background:white;border-radius:8px;padding:24px;box-shadow:0 1px 4px rgba(0,0,0,0.08)"><div style="color:#f59e0b;font-size:1.1rem;margin-bottom:10px">★★★★★</div><p style="font-size:14px;color:#444;margin-bottom:16px">"The ROI was immediate. Best investment we have made this year. Highly recommend to any serious marketer."</p><div style="display:flex;align-items:center;gap:10px"><div style="width:36px;height:36px;border-radius:50%;background:#dcfce7;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:14px">MC</div><div><div style="font-weight:600;font-size:13px">Mark Chen</div><div style="font-size:11px;color:#888">Founder, GrowthLabs</div></div></div></div><div style="background:white;border-radius:8px;padding:24px;box-shadow:0 1px 4px rgba(0,0,0,0.08)"><div style="color:#f59e0b;font-size:1.1rem;margin-bottom:10px">★★★★★</div><p style="font-size:14px;color:#444;margin-bottom:16px">"Incredible support and the product delivers exactly what it promises. Our entire team loves it."</p><div style="display:flex;align-items:center;gap:10px"><div style="width:36px;height:36px;border-radius:50%;background:#fee2e2;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:14px">AT</div><div><div style="font-weight:600;font-size:13px">Amanda Torres</div><div style="font-size:11px;color:#888">CMO, ScaleUp Inc</div></div></div></div></div></div></section>'
|
|
271
|
-
},
|
|
272
|
-
{
|
|
273
|
-
key: "cro/urgency-banner",
|
|
274
|
-
name: "Urgency Banner",
|
|
275
|
-
icon: "\u23F0",
|
|
276
|
-
desc: "Countdown timer + limited-time offer",
|
|
277
|
-
html: '<div style="background:#ef4444;color:white;text-align:center;padding:14px;font-size:14px;font-weight:500">🔥 Limited time offer: <strong>50% OFF</strong> ends in <span style="font-family:monospace;font-size:1rem;font-weight:700;background:rgba(0,0,0,0.2);padding:2px 10px;border-radius:4px;margin:0 6px">23:47:12</span>— <a href="#" style="color:white;font-weight:700;text-decoration:underline">Claim your discount →</a></div>'
|
|
278
|
-
},
|
|
279
|
-
{
|
|
280
|
-
key: "cro/trust-badges",
|
|
281
|
-
name: "Trust Badges",
|
|
282
|
-
icon: "\u{1F6E1}\uFE0F",
|
|
283
|
-
desc: "Security seals, payment icons, guarantees",
|
|
284
|
-
html: '<div style="padding:28px 20px;border-top:1px solid #e5e5e5;border-bottom:1px solid #e5e5e5;background:white"><div style="display:flex;flex-wrap:wrap;justify-content:center;align-items:center;gap:32px;max-width:700px;margin:0 auto"><div style="text-align:center;font-size:12px;color:#555"><div style="font-size:28px;margin-bottom:6px">🔒</div><div style="font-weight:600">SSL Secure</div><div style="font-size:10px;color:#888">256-bit encryption</div></div><div style="text-align:center;font-size:12px;color:#555"><div style="font-size:28px;margin-bottom:6px">↵</div><div style="font-weight:600">30-Day Guarantee</div><div style="font-size:10px;color:#888">Money back, no questions</div></div><div style="text-align:center;font-size:12px;color:#555"><div style="font-size:28px;margin-bottom:6px">⭐</div><div style="font-weight:600">4.9 / 5 Rating</div><div style="font-size:10px;color:#888">From 2,400+ reviews</div></div><div style="text-align:center;font-size:12px;color:#555"><div style="font-size:28px;margin-bottom:6px">💳</div><div style="font-weight:600">Secure Payment</div><div style="font-size:10px;color:#888">Visa · MC · PayPal</div></div></div></div>'
|
|
285
|
-
},
|
|
286
|
-
{
|
|
287
|
-
key: "cro/cta-block",
|
|
288
|
-
name: "CTA Block",
|
|
289
|
-
icon: "\u{1F4E3}",
|
|
290
|
-
desc: "Dark high-impact call-to-action section",
|
|
291
|
-
html: '<section style="background:#1a1a2e;color:white;padding:64px 20px;text-align:center"><div style="max-width:600px;margin:0 auto"><h2 style="font-size:2rem;font-weight:800;color:white;margin-bottom:10px">Ready to get started?</h2><p style="opacity:0.7;margin-bottom:32px">Join 10,000+ companies already seeing results with our platform.</p><div style="display:flex;gap:12px;justify-content:center;flex-wrap:wrap"><a href="#" style="display:inline-block;background:#f59e0b;color:white;padding:14px 36px;border-radius:6px;font-weight:700;text-decoration:none;font-size:1rem">Start Free Trial</a><a href="#" style="display:inline-block;border:2px solid rgba(255,255,255,0.4);color:white;padding:14px 36px;border-radius:6px;font-weight:600;text-decoration:none;font-size:1rem">Schedule Demo</a></div><p style="font-size:12px;margin-top:18px;opacity:0.45">No credit card required · Cancel anytime</p></div></section>'
|
|
292
|
-
},
|
|
293
|
-
{
|
|
294
|
-
key: "cro/feature-grid",
|
|
295
|
-
name: "Feature Grid",
|
|
296
|
-
icon: "\u2728",
|
|
297
|
-
desc: "3-column key benefits grid",
|
|
298
|
-
html: '<section style="padding:60px 20px;background:white"><div style="max-width:900px;margin:0 auto"><h2 style="text-align:center;font-size:1.8rem;font-weight:800;margin-bottom:48px">Why choose us?</h2><div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:32px;text-align:center"><div><div style="font-size:2.5rem;margin-bottom:14px">🚀</div><h5 style="font-weight:700;margin-bottom:8px">Fast Results</h5><p style="color:#666;font-size:14px">See improvements in your conversion rate within the first 30 days or your money back.</p></div><div><div style="font-size:2.5rem;margin-bottom:14px">📊</div><h5 style="font-weight:700;margin-bottom:8px">Data-Driven</h5><p style="color:#666;font-size:14px">Every decision backed by real user data and statistical significance testing.</p></div><div><div style="font-size:2.5rem;margin-bottom:14px">🎯</div><h5 style="font-weight:700;margin-bottom:8px">Precision Targeting</h5><p style="color:#666;font-size:14px">Target the right audience segments with personalized, high-converting experiences.</p></div></div></div></section>'
|
|
299
|
-
},
|
|
300
|
-
{
|
|
301
|
-
key: "cro/exit-intent-bar",
|
|
302
|
-
name: "Exit Intent Bar",
|
|
303
|
-
icon: "\u{1F6AA}",
|
|
304
|
-
desc: "Sticky bottom bar for exit-intent capture",
|
|
305
|
-
html: `<div style="position:fixed;bottom:0;left:0;right:0;background:#1e293b;color:white;padding:14px 20px;display:flex;align-items:center;justify-content:center;gap:16px;z-index:9999;box-shadow:0 -4px 20px rgba(0,0,0,0.2)"><span style="font-size:14px">🔔 <strong>Wait!</strong> Don't leave empty-handed — get 20% off your first order.</span><a href="#" style="background:#f59e0b;color:white;padding:8px 20px;border-radius:4px;font-weight:700;text-decoration:none;font-size:13px;white-space:nowrap">Claim Offer</a><a href="#" style="color:rgba(255,255,255,0.5);font-size:12px;text-decoration:none">No thanks</a></div>`
|
|
306
|
-
},
|
|
307
|
-
{
|
|
308
|
-
key: "cro/pricing-table",
|
|
309
|
-
name: "Pricing Table",
|
|
310
|
-
icon: "\u{1F4B0}",
|
|
311
|
-
desc: "3-tier pricing with highlighted plan",
|
|
312
|
-
html: '<section style="padding:60px 20px;background:#f8fafc"><div style="max-width:900px;margin:0 auto"><h2 style="text-align:center;font-weight:800;font-size:1.8rem;margin-bottom:8px">Simple, transparent pricing</h2><p style="text-align:center;color:#666;margin-bottom:48px">No hidden fees. Cancel anytime.</p><div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:20px"><div style="background:white;border:1px solid #e5e5e5;border-radius:10px;padding:28px"><h3 style="font-weight:700;margin-bottom:6px">Starter</h3><div style="font-size:2rem;font-weight:800;margin-bottom:16px">$29<span style="font-size:1rem;font-weight:400;color:#888">/mo</span></div><ul style="list-style:none;padding:0;font-size:14px;color:#555;margin-bottom:24px"><li style="padding:6px 0;border-bottom:1px solid #f0f0f0">✓ Up to 10,000 visitors/mo</li><li style="padding:6px 0;border-bottom:1px solid #f0f0f0">✓ 5 A/B tests</li><li style="padding:6px 0">✓ Email support</li></ul><a href="#" style="display:block;text-align:center;border:2px solid #e5e5e5;padding:10px;border-radius:6px;font-weight:600;text-decoration:none;color:#333">Get started</a></div><div style="background:#3b82f6;border-radius:10px;padding:28px;position:relative;transform:scale(1.04);box-shadow:0 8px 32px rgba(59,130,246,0.3)"><div style="position:absolute;top:-12px;left:50%;transform:translateX(-50%);background:#f59e0b;color:white;font-size:11px;font-weight:700;padding:4px 12px;border-radius:20px">MOST POPULAR</div><h3 style="font-weight:700;margin-bottom:6px;color:white">Pro</h3><div style="font-size:2rem;font-weight:800;margin-bottom:16px;color:white">$79<span style="font-size:1rem;font-weight:400;opacity:0.7">/mo</span></div><ul style="list-style:none;padding:0;font-size:14px;color:rgba(255,255,255,0.85);margin-bottom:24px"><li style="padding:6px 0;border-bottom:1px solid rgba(255,255,255,0.15)">✓ Up to 100,000 visitors/mo</li><li style="padding:6px 0;border-bottom:1px solid rgba(255,255,255,0.15)">✓ Unlimited A/B tests</li><li style="padding:6px 0">✓ Priority support</li></ul><a href="#" style="display:block;text-align:center;background:white;color:#3b82f6;padding:10px;border-radius:6px;font-weight:700;text-decoration:none">Get started</a></div><div style="background:white;border:1px solid #e5e5e5;border-radius:10px;padding:28px"><h3 style="font-weight:700;margin-bottom:6px">Enterprise</h3><div style="font-size:2rem;font-weight:800;margin-bottom:16px">Custom</div><ul style="list-style:none;padding:0;font-size:14px;color:#555;margin-bottom:24px"><li style="padding:6px 0;border-bottom:1px solid #f0f0f0">✓ Unlimited visitors</li><li style="padding:6px 0;border-bottom:1px solid #f0f0f0">✓ White-label option</li><li style="padding:6px 0">✓ Dedicated support</li></ul><a href="#" style="display:block;text-align:center;border:2px solid #e5e5e5;padding:10px;border-radius:6px;font-weight:600;text-decoration:none;color:#333">Contact sales</a></div></div></div></section>'
|
|
313
|
-
}
|
|
314
|
-
];
|
|
315
359
|
const sectionsJson = JSON.stringify(CRO_SECTIONS);
|
|
316
360
|
return `<!DOCTYPE html>
|
|
317
361
|
<html lang="en">
|
|
@@ -319,27 +363,39 @@ function buildVvvebEditorHtml() {
|
|
|
319
363
|
<meta charset="UTF-8">
|
|
320
364
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
321
365
|
<title>Visual Editor V2</title>
|
|
366
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
367
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
368
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">
|
|
322
369
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
|
323
370
|
<style>
|
|
324
371
|
/* \u2500\u2500 Reset \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
325
372
|
*{box-sizing:border-box;margin:0;padding:0}
|
|
326
|
-
html,body{height:100%;overflow:hidden;font-family
|
|
373
|
+
html,body{height:100%;overflow:hidden;font-family:var(--font-sans);font-size:13px;color:#1e293b;background:#f1f5f9}
|
|
327
374
|
|
|
328
375
|
/* \u2500\u2500 CSS variables \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
329
376
|
:root{
|
|
377
|
+
--font-inter:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
|
|
378
|
+
--font-roboto:'Roboto',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
|
|
379
|
+
--font-mono:'JetBrains Mono',ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;
|
|
380
|
+
--font-sans:var(--font-inter),var(--font-roboto),-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
|
|
330
381
|
--bg: #ffffff;
|
|
331
382
|
--bg-sub: #f8fafc;
|
|
332
|
-
--bg-hover: #
|
|
383
|
+
--bg-hover: #F5F5F5;
|
|
333
384
|
--border: #e2e8f0;
|
|
334
385
|
--border-sub: #f1f5f9;
|
|
335
386
|
--text: #404040;
|
|
336
387
|
--text-2: #475569;
|
|
337
388
|
--text-3: #94a3b8;
|
|
338
|
-
--accent: #
|
|
339
|
-
--accent-bg: #
|
|
389
|
+
--accent: #262626;
|
|
390
|
+
--accent-bg: #f5f5f5;
|
|
340
391
|
--accent-txt: #404040;
|
|
341
392
|
}
|
|
342
393
|
|
|
394
|
+
/* \u2500\u2500 Font utilities \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
395
|
+
.inter{font-family:var(--font-inter)}
|
|
396
|
+
.roboto{font-family:var(--font-roboto)}
|
|
397
|
+
.mono{font-family:var(--font-mono)}
|
|
398
|
+
|
|
343
399
|
/* \u2500\u2500 Layout \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
344
400
|
#app{display:flex;flex-direction:column;height:100vh}
|
|
345
401
|
#main{display:flex;flex:1;overflow:hidden;min-height:0}
|
|
@@ -417,9 +473,32 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
417
473
|
border-color:transparent;
|
|
418
474
|
}
|
|
419
475
|
.tb-dev-menu input#dev-zoom-level{
|
|
420
|
-
max-width:
|
|
421
|
-
margin-left:
|
|
476
|
+
max-width:72px;
|
|
477
|
+
margin-left:0;
|
|
422
478
|
}
|
|
479
|
+
.tb-dev-menu .row-zoom .zoom-controls{
|
|
480
|
+
display:flex;
|
|
481
|
+
align-items:center;
|
|
482
|
+
gap:6px;
|
|
483
|
+
margin-left:auto;
|
|
484
|
+
}
|
|
485
|
+
.tb-dev-menu .dev-zoom-fit-btn{
|
|
486
|
+
width:30px;
|
|
487
|
+
height:30px;
|
|
488
|
+
flex-shrink:0;
|
|
489
|
+
border:none;
|
|
490
|
+
border-radius:6px;
|
|
491
|
+
background:#fff;
|
|
492
|
+
cursor:pointer;
|
|
493
|
+
display:flex;
|
|
494
|
+
align-items:center;
|
|
495
|
+
justify-content:center;
|
|
496
|
+
color:#404040;
|
|
497
|
+
box-shadow:0 0 1px 0 rgba(0,0,0,.20),0 1px 2px 0 rgba(0,0,0,.05),0 1px 1px 0 rgba(0,0,0,.01);
|
|
498
|
+
transition:background .12s,color .12s;
|
|
499
|
+
}
|
|
500
|
+
.tb-dev-menu .dev-zoom-fit-btn:hover{background:#f4f4f5;color:#171717}
|
|
501
|
+
.tb-dev-menu .dev-zoom-fit-btn svg{display:block;width:16px;height:16px}
|
|
423
502
|
.tb-dev-menu input:focus{
|
|
424
503
|
border-color:#1A1A1A;
|
|
425
504
|
box-shadow:0 0 0 2px rgba(99,102,241,.14)
|
|
@@ -449,19 +528,10 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
449
528
|
text-overflow: ellipsis;
|
|
450
529
|
font-size: var(--font-size-sm, 14px);
|
|
451
530
|
font-style: normal;
|
|
452
|
-
font-weight: 500
|
|
531
|
+
font-weight: 500;#
|
|
453
532
|
line-height: var(--font-leading-4, 16px);
|
|
454
533
|
}
|
|
455
534
|
.tb-dev-menu .vp-preset-btn:hover,.tb-dev-menu .vp-preset-btn.active{background:#f4f4f5}
|
|
456
|
-
.tb-dev-menu .ft{
|
|
457
|
-
margin-top:10px;padding-top:8px;border-top:1px solid #ececf0;
|
|
458
|
-
display:flex;justify-content:flex-end
|
|
459
|
-
}
|
|
460
|
-
.tb-dev-menu .apply-btn{
|
|
461
|
-
border:1px solid #d4d4d8;background:#f8fafc;color:#111827;border-radius:6px;
|
|
462
|
-
height:30px;padding:0 10px;font-size:12px;font-weight:600;cursor:pointer
|
|
463
|
-
}
|
|
464
|
-
.tb-dev-menu .apply-btn:hover{background:#eef2ff;border-color:#a5b4fc}
|
|
465
535
|
/* Dark icon buttons */
|
|
466
536
|
.tb-dk-btn{width:28px;height:28px;background:transparent;border:none;border-radius:5px;cursor:pointer;color:#71717a;display:flex;align-items:center;justify-content:center;font-size:13px;transition:all .12s;flex-shrink:0}
|
|
467
537
|
.tb-dk-btn:hover{color:#e4e4e7;background:rgba(255,255,255,.07)}
|
|
@@ -492,9 +562,29 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
492
562
|
.tb-sim-btn{background:transparent;border:1px solid #e5e7eb;border-radius:6px;color:#404040;cursor:pointer;font-size:14px;font-weight:500;padding:6px 10px;display:flex;align-items:center;gap:5px;transition:all .15s;white-space:nowrap;font-family:inherit}
|
|
493
563
|
.tb-sim-btn:hover{background:rgba(255,255,255,.06);border-color:#52525b}
|
|
494
564
|
.tb-sim-btn i{font-size:11px}
|
|
495
|
-
.tb-fin-btn{
|
|
496
|
-
|
|
497
|
-
|
|
565
|
+
.tb-fin-btn{ border: none;
|
|
566
|
+
cursor: pointer;
|
|
567
|
+
transition: all .15s;
|
|
568
|
+
white-space: nowrap;
|
|
569
|
+
border-radius: var(--radius-md, 6px);
|
|
570
|
+
background: var(--bg-primary-default, #262626);
|
|
571
|
+
padding: 7px 10px;
|
|
572
|
+
color: var(--content-on-color, #FFF);
|
|
573
|
+
text-align: center;
|
|
574
|
+
font-family: Inter;
|
|
575
|
+
font-size: var(--font-size-sm, 14px);
|
|
576
|
+
font-style: normal;
|
|
577
|
+
font-weight: 500;
|
|
578
|
+
line-height: var(--font-leading-4, 16px);
|
|
579
|
+
}
|
|
580
|
+
.tb-fin-btn:hover{opacity:0.8;}
|
|
581
|
+
.tb-fin-btn#btn-save{
|
|
582
|
+
background: var(--bg-interactive-default, #FFF);
|
|
583
|
+
box-shadow: 0 0 1px 0 var(--Black-20, rgba(0, 0, 0, 0.20)), 0 1px 2px 0 var(--Black-5, rgba(0, 0, 0, 0.05)), 0 1px 1px 0 rgba(0, 0, 0, 0.01);
|
|
584
|
+
border: none;
|
|
585
|
+
color: var(--content-success-default, #00C951);
|
|
586
|
+
font-weight: 500;
|
|
587
|
+
}
|
|
498
588
|
/* \u2500\u2500 Page loading hint (toolbar + sidebar) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
499
589
|
.tb-page-loading{
|
|
500
590
|
display:none;flex-shrink:0;align-items:center;margin:0 10px 0 4px;
|
|
@@ -551,14 +641,17 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
551
641
|
|
|
552
642
|
/* \u2500\u2500 Left panel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
553
643
|
#left-panel{
|
|
554
|
-
width:
|
|
555
|
-
display:flex;flex-direction:column;flex-shrink:0;min-height:0;overflow:hidden
|
|
644
|
+
width:288px;
|
|
645
|
+
display:flex;flex-direction:column;flex-shrink:0;min-height:0;overflow:hidden;
|
|
646
|
+
border-right: 1px solid var(--border-default, #E5E5E5);
|
|
647
|
+
background: var(--cu-Background-Main, #FFF);
|
|
556
648
|
}
|
|
557
649
|
|
|
558
650
|
/* \u2500\u2500 Iframe panel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
559
651
|
#iframe-panel{
|
|
560
652
|
flex:1;background:#e8ecf0;display:flex;flex-direction:column;
|
|
561
|
-
align-items:center;justify-content:flex-start;overflow:
|
|
653
|
+
align-items:center;justify-content:flex-start;overflow:hidden;position:relative;
|
|
654
|
+
min-height:0;min-width:0
|
|
562
655
|
}
|
|
563
656
|
|
|
564
657
|
/* \u2500\u2500 Floating selection toolbar (above iframe selection) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
@@ -579,13 +672,34 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
579
672
|
#selection-floater .sf-sep{width:1px;height:16px;background:var(--border);margin:0 2px;flex-shrink:0}
|
|
580
673
|
|
|
581
674
|
/* \u2500\u2500 DOM tree (Elements tab) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
582
|
-
.dt-tree{
|
|
675
|
+
.dt-tree{user-select:none}
|
|
583
676
|
.dt-row{
|
|
584
|
-
|
|
585
|
-
|
|
677
|
+
width: 100%;
|
|
678
|
+
display: flex;
|
|
679
|
+
align-items: center;
|
|
680
|
+
gap: 2px;
|
|
681
|
+
min-height: 26px;
|
|
682
|
+
padding: 10px 8px 10px 4px;
|
|
683
|
+
cursor: pointer;
|
|
684
|
+
color: var(--text-2);
|
|
685
|
+
position: relative;
|
|
586
686
|
}
|
|
587
687
|
.dt-row:hover{background:var(--bg-hover);color:var(--text)}
|
|
588
|
-
.dt-row.dt-selected{background
|
|
688
|
+
.dt-row.dt-selected{position:relative;background:var(--bg-hover);}
|
|
689
|
+
.dt-row.dt-selected::before, .dt-row:hover::before{
|
|
690
|
+
display: block;
|
|
691
|
+
content: '';
|
|
692
|
+
position: absolute;
|
|
693
|
+
top: 0;
|
|
694
|
+
left: 0px;
|
|
695
|
+
height: 100%;
|
|
696
|
+
width: 2px;
|
|
697
|
+
background: #262626;
|
|
698
|
+
}
|
|
699
|
+
.dt-row.dt-selected .dt-lbl .dt-tag{
|
|
700
|
+
background: var(--bg-primary-default, #262626)!important;
|
|
701
|
+
color: var(--text-primary-default, #FFF)!important;
|
|
702
|
+
}
|
|
589
703
|
.dt-chev{
|
|
590
704
|
width:16px;height:16px;flex-shrink:0;border:none;background:transparent;
|
|
591
705
|
cursor:pointer;color:var(--text-3);display:flex;align-items:center;justify-content:center;
|
|
@@ -594,22 +708,36 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
594
708
|
.dt-chev:hover{color:var(--text)}
|
|
595
709
|
.dt-chev.dt-spacer{visibility:hidden;pointer-events:none}
|
|
596
710
|
.dt-ico{width:16px;flex-shrink:0;text-align:center;color:var(--text-3);font-size:12px}
|
|
597
|
-
.dt-lbl{
|
|
711
|
+
.dt-lbl{
|
|
712
|
+
flex: 1;
|
|
713
|
+
overflow: hidden;
|
|
714
|
+
text-overflow: ellipsis;
|
|
715
|
+
white-space: nowrap;
|
|
716
|
+
color: var(--content-strong, #171717);
|
|
717
|
+
font-family: "JetBrains Mono";
|
|
718
|
+
}
|
|
598
719
|
.dt-muted{padding:16px 12px;text-align:center;color:var(--text-3);font-size:11px;line-height:1.4}
|
|
599
720
|
#section-components-panel{
|
|
600
721
|
max-height: 50%;
|
|
601
722
|
overflow-y: auto;
|
|
723
|
+
flex-shrink: 0;
|
|
724
|
+
display: flex;
|
|
725
|
+
flex-direction: column;
|
|
602
726
|
}
|
|
727
|
+
#section-components-panel .lp-body.collapsed{display:none}
|
|
603
728
|
/* \u2500\u2500 Right panel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
604
729
|
#right-panel{
|
|
605
|
-
width:
|
|
730
|
+
width:288px;
|
|
731
|
+
border-left: 1px solid var(--border-default, #E5E5E5);
|
|
732
|
+
background: var(--cu-Background-Main, #FFF);
|
|
606
733
|
display:flex;flex-direction:column;flex-shrink:0;overflow:hidden
|
|
607
734
|
}
|
|
608
735
|
|
|
609
736
|
/* \u2500\u2500 Breadcrumb \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
610
737
|
#breadcrumb{
|
|
738
|
+
display:none;
|
|
611
739
|
height:26px;background:var(--bg);border-top:1px solid var(--border);
|
|
612
|
-
|
|
740
|
+
align-items:center;padding:0 12px;font-size:11px;
|
|
613
741
|
color:var(--text-3);flex-shrink:0;gap:5px;overflow:hidden
|
|
614
742
|
}
|
|
615
743
|
|
|
@@ -622,9 +750,13 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
622
750
|
|
|
623
751
|
/* \u2500\u2500 Device frame \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
624
752
|
#device-frame{
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
753
|
+
width: 100%;
|
|
754
|
+
min-height: 100%;
|
|
755
|
+
display: flex;
|
|
756
|
+
align-items: center;
|
|
757
|
+
transform-origin: top left;
|
|
758
|
+
transition: max-width .3s ease,width .2s ease,height .2s ease;
|
|
759
|
+
flex-shrink: 0;
|
|
628
760
|
}
|
|
629
761
|
#device-frame.desktop{
|
|
630
762
|
max-width:1440px;
|
|
@@ -675,33 +807,51 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
675
807
|
}
|
|
676
808
|
|
|
677
809
|
/* \u2500\u2500 Left panel sections \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
678
|
-
.lp-sec{border-bottom:1px solid var(--border);flex-shrink:0;padding: 24px;}
|
|
810
|
+
.lp-sec{border-bottom:1px solid var(--border);flex-shrink:0;padding: 24px 16px;}
|
|
679
811
|
.lp-sec-no-border{border-bottom:none!important}
|
|
680
812
|
.lp-sec-hd{
|
|
681
813
|
margin-bottom: 12px;
|
|
682
814
|
font-size:14px;font-weight:600;
|
|
815
|
+
line-height: 20px;
|
|
683
816
|
color:#404040;display:flex;align-items:center;justify-content:space-between;gap:5px
|
|
684
817
|
}
|
|
685
818
|
.lp-sec-hd-left{display:flex;align-items:center;gap:5px}
|
|
686
819
|
#active-var-label{display:none;color:var(--accent-txt);font-size:10px;font-weight:500}
|
|
687
820
|
.lp-info-icon{font-size:11px;color:var(--text-3);cursor:default;opacity:.7}
|
|
688
821
|
.lp-add-btn{
|
|
689
|
-
|
|
690
|
-
|
|
822
|
+
background: none;
|
|
823
|
+
border: none;
|
|
824
|
+
cursor: pointer;
|
|
825
|
+
padding: 2px 5px;
|
|
826
|
+
border-radius: 4px;
|
|
827
|
+
transition: all .12s;
|
|
828
|
+
flex-shrink: 0;
|
|
829
|
+
color: var(--content-default, #404040);
|
|
830
|
+
text-align: center;
|
|
831
|
+
font-family: Inter;
|
|
832
|
+
font-size: 12px;
|
|
833
|
+
font-style: normal;
|
|
834
|
+
font-weight: 500;
|
|
835
|
+
line-height: 14px;
|
|
691
836
|
}
|
|
692
|
-
.lp-add-btn:hover{
|
|
837
|
+
.lp-add-btn:hover{opacity:0.8}
|
|
693
838
|
|
|
694
839
|
/* \u2500\u2500 Variation tabs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
695
840
|
#variation-tabs{display:flex;flex-direction:column; gap:8px;}
|
|
696
841
|
.var-tab{
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
842
|
+
border-radius: var(--radius-md, 6px);
|
|
843
|
+
border:1px solid transparent;
|
|
844
|
+
background: var(--bg-interactive-default, #FFF);
|
|
845
|
+
box-shadow: 0 0 1px 0 var(--Black-20, rgba(0, 0, 0, 0.20)), 0 1px 2px 0 var(--Black-5, rgba(0, 0, 0, 0.05)), 0 1px 1px 0 rgba(0, 0, 0, 0.01);
|
|
846
|
+
cursor:pointer;font-size:15px;font-weight:500;padding:7px 10px;transition:background .12s,color .12s,border-color .12s;
|
|
701
847
|
width:100%;text-align:left;display:flex;align-items:center;gap:8px;
|
|
848
|
+
line-height: 16px;
|
|
702
849
|
}
|
|
703
850
|
.var-tab:hover{background:var(--bg-hover);color:var(--text)}
|
|
704
|
-
.var-tab.active{
|
|
851
|
+
button.var-tab.active{
|
|
852
|
+
color:var(--accent-txt);
|
|
853
|
+
border-color:var(--var-tab-color, transparent);
|
|
854
|
+
}
|
|
705
855
|
.var-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}
|
|
706
856
|
.var-add-row{
|
|
707
857
|
display:none!important;
|
|
@@ -715,51 +865,207 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
715
865
|
.var-add-row:hover{color:var(--accent-txt)}
|
|
716
866
|
|
|
717
867
|
/* \u2500\u2500 Search \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
868
|
+
.lp-search-container{margin-bottom:8px}
|
|
869
|
+
.lp-search-field{
|
|
870
|
+
position:relative;
|
|
871
|
+
display:flex;
|
|
872
|
+
align-items:center;
|
|
873
|
+
width:100%;
|
|
874
|
+
}
|
|
875
|
+
.lp-search-icon{
|
|
876
|
+
position:absolute;
|
|
877
|
+
left:12px;
|
|
878
|
+
top:50%;
|
|
879
|
+
transform:translateY(-50%);
|
|
880
|
+
display:flex;
|
|
881
|
+
align-items:center;
|
|
882
|
+
justify-content:center;
|
|
883
|
+
width:16px;
|
|
884
|
+
height:16px;
|
|
885
|
+
pointer-events:none;
|
|
886
|
+
color:var(--base-sub-2,#B5B5B5);
|
|
887
|
+
flex-shrink:0;
|
|
888
|
+
}
|
|
889
|
+
.lp-search-icon svg{display:block;width:16px;height:16px}
|
|
890
|
+
.lp-search-icon svg path{stroke:currentColor}
|
|
718
891
|
#comp-search{
|
|
719
|
-
|
|
720
|
-
color:var(--text);
|
|
892
|
+
border:1px solid var(--border);
|
|
893
|
+
color:var(--text);
|
|
894
|
+
font-size:12px;
|
|
895
|
+
padding:9px 12px 9px 36px;
|
|
896
|
+
width:100%;
|
|
897
|
+
outline:none;
|
|
898
|
+
border-radius:6px;
|
|
899
|
+
background:var(--Greyscale-0,#FFF);
|
|
900
|
+
box-shadow:0 0 1px 0 var(--Black-20,rgba(0,0,0,.20)),0 1px 2px 0 var(--Black-5,rgba(0,0,0,.05)),0 1px 1px 0 rgba(0,0,0,.01);
|
|
721
901
|
}
|
|
722
|
-
#comp-search::placeholder{
|
|
723
|
-
|
|
724
|
-
|
|
902
|
+
#comp-search::placeholder{
|
|
903
|
+
color:var(--base-sub-2,#B5B5B5);
|
|
904
|
+
font-size:var(--font-size-sm,14px);
|
|
905
|
+
font-style:normal;
|
|
906
|
+
font-weight:500;
|
|
907
|
+
}
|
|
908
|
+
#comp-search:focus{border-color:#000;}
|
|
725
909
|
/* \u2500\u2500 Left tabs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
726
|
-
.lp-tabs
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
910
|
+
.lp-tabs-container{
|
|
911
|
+
display:flex;
|
|
912
|
+
align-items:center;
|
|
913
|
+
justify-content:space-between;
|
|
730
914
|
}
|
|
731
|
-
.lp-
|
|
732
|
-
|
|
733
|
-
|
|
915
|
+
.lp-tabs{
|
|
916
|
+
width: 100%;
|
|
917
|
+
padding: 4px 10px;
|
|
918
|
+
flex: 1;
|
|
734
919
|
display: flex;
|
|
735
|
-
|
|
920
|
+
border-radius: 6px;
|
|
921
|
+
background: var(--base-soft-2,#F0F0F0);
|
|
922
|
+
padding: 4px 6px;
|
|
923
|
+
flex-shrink: 0;
|
|
924
|
+
gap: 6px;
|
|
925
|
+
align-items: center;
|
|
926
|
+
white-space: nowrap;
|
|
927
|
+
}
|
|
928
|
+
.lp-tab{
|
|
929
|
+
flex: 1;
|
|
930
|
+
text-align: center;
|
|
931
|
+
color: #404040;
|
|
932
|
+
white-space: nowrap;
|
|
933
|
+
cursor: pointer;
|
|
934
|
+
transition: all .15s;
|
|
935
|
+
line-height: 1.15;
|
|
936
|
+
font-size: var(--font-size-sm,14px);
|
|
937
|
+
font-weight: 500;
|
|
938
|
+
padding:4px 10px;
|
|
939
|
+
}
|
|
940
|
+
.section-components-tabs-container{
|
|
941
|
+
display: flex;
|
|
736
942
|
align-items: center;
|
|
737
|
-
justify-content:
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
943
|
+
justify-content: space-between;
|
|
944
|
+
flex-shrink: 0;
|
|
945
|
+
padding: 12px 16px;
|
|
946
|
+
border-bottom: 1px solid #F5F5F5;
|
|
947
|
+
}
|
|
948
|
+
.section-components-tabs-container .lp-tabs{
|
|
949
|
+
flex:1;
|
|
741
950
|
}
|
|
951
|
+
.lp-tab.close-section-components-panel{
|
|
952
|
+
flex:0 0 auto;
|
|
953
|
+
flex-shrink:0;
|
|
954
|
+
display:flex;
|
|
955
|
+
align-items:center;
|
|
956
|
+
justify-content:center;
|
|
957
|
+
width:24px;
|
|
958
|
+
height:24px;
|
|
959
|
+
padding:0;
|
|
960
|
+
background:none;
|
|
961
|
+
border-radius:4px;
|
|
962
|
+
color:var(--content-default,#404040);
|
|
963
|
+
line-height:1;
|
|
964
|
+
white-space:nowrap;
|
|
965
|
+
}
|
|
966
|
+
.lp-tab.close-section-components-panel i{
|
|
967
|
+
font-size:14px;
|
|
968
|
+
line-height:1;
|
|
969
|
+
transition:transform .15s;
|
|
970
|
+
}
|
|
971
|
+
.lp-tab.close-section-components-panel.collapsed i{transform:rotate(-180deg)}
|
|
742
972
|
.lp-tab:hover{color:var(--text-2)}
|
|
743
|
-
.lp-tab.active{
|
|
973
|
+
.lp-tab.active{
|
|
974
|
+
border-radius:4px;
|
|
975
|
+
background:var(--bg-interactive-default,#FFF);
|
|
976
|
+
box-shadow:0 0 1px 0 var(--Black-20,rgba(0,0,0,.20)),0 1px 2px 0 var(--Black-5,rgba(0,0,0,.05)),0 1px 1px 0 rgba(0,0,0,.01);
|
|
977
|
+
}
|
|
978
|
+
.lp-tab.close-section-components-panel:hover{opacity:.8;color:var(--text-2)}
|
|
979
|
+
.lp-tab.close-section-components-panel.active{
|
|
980
|
+
background:none;
|
|
981
|
+
box-shadow:none;
|
|
982
|
+
border-radius:4px;
|
|
983
|
+
}
|
|
744
984
|
.future-hidden{display:none!important}
|
|
745
985
|
|
|
746
986
|
/* \u2500\u2500 Left panel body \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
987
|
+
.lp-body #tab-dom-tree, .lp-body #tab-elements{
|
|
988
|
+
padding-top:4px;
|
|
989
|
+
}
|
|
990
|
+
.lp-body #tab-elements .dt-lbl{
|
|
991
|
+
font-size: 12px;
|
|
992
|
+
font-style: normal;
|
|
993
|
+
font-weight: 500;
|
|
994
|
+
line-height: 14px;
|
|
995
|
+
letter-spacing: -0.1px;
|
|
996
|
+
}
|
|
997
|
+
.lp-body #tab-elements #elements-root > .dt-row{
|
|
998
|
+
padding-left: 16px!important;
|
|
999
|
+
}
|
|
1000
|
+
.lp-body #dom-tree-root .dt-lbl{
|
|
1001
|
+
color: var(--content-subtle, #737373);
|
|
1002
|
+
font-style: normal;
|
|
1003
|
+
font-weight: 400;
|
|
1004
|
+
line-height: var(--font-leading-3, 12px); /* 100% */
|
|
1005
|
+
letter-spacing: -0.1px;
|
|
1006
|
+
}
|
|
1007
|
+
.lp-body #dom-tree-root .dt-lbl .dt-tag{
|
|
1008
|
+
color: var(--content-strong, #171717);
|
|
1009
|
+
font-family: "JetBrains Mono";
|
|
1010
|
+
font-size: 12px;
|
|
1011
|
+
font-style: normal;
|
|
1012
|
+
font-weight: 500;
|
|
1013
|
+
line-height: 14px;
|
|
1014
|
+
letter-spacing: -0.1px;
|
|
1015
|
+
border-radius: 4px;
|
|
1016
|
+
background: var(--bg-surface-subtle, #F5F5F5);
|
|
1017
|
+
padding:3px 6px;
|
|
1018
|
+
display:inline-block;
|
|
1019
|
+
margin-right:4px;
|
|
1020
|
+
}
|
|
1021
|
+
.lp-body #tab-elements .dt-row .dt-chev.dt-spacer{display:none;}
|
|
1022
|
+
.lp-body #tab-dom-tree .dt-row .dt-ico{display:none;}
|
|
747
1023
|
.lp-body, .section-components-body{flex:1;overflow-y:auto}
|
|
748
1024
|
.lp-body::-webkit-scrollbar, .section-components-body::-webkit-scrollbar{width:3px}
|
|
749
1025
|
.lp-body::-webkit-scrollbar-thumb, .section-components-body::-webkit-scrollbar-thumb{background:#cbd5e1;border-radius:2px}
|
|
750
1026
|
.tab-pane, .section-components-tab-pane{display:none}.tab-pane.active, .section-components-tab-pane.active{display:block}
|
|
751
1027
|
|
|
752
1028
|
/* \u2500\u2500 Component grid \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
753
|
-
.cg-hdr{padding:
|
|
754
|
-
|
|
1029
|
+
.cg-hdr{ padding: 12px 12px;
|
|
1030
|
+
text-transform: uppercase;
|
|
1031
|
+
letter-spacing: .06em;
|
|
1032
|
+
color: var(--content-subtle, #737373);
|
|
1033
|
+
font-family: Inter;
|
|
1034
|
+
font-size: 12px;
|
|
1035
|
+
font-weight: 600;
|
|
1036
|
+
line-height: normal;
|
|
1037
|
+
}
|
|
1038
|
+
.cg-grid{ display: grid;
|
|
1039
|
+
grid-template-columns: 1fr 1fr 1fr;
|
|
1040
|
+
padding: 0 12px 12px;
|
|
1041
|
+
column-gap: 8px;
|
|
1042
|
+
row-gap: 12px;}
|
|
755
1043
|
.cg-item{
|
|
756
|
-
|
|
757
|
-
|
|
1044
|
+
background: #fff;
|
|
1045
|
+
cursor: pointer;
|
|
1046
|
+
padding: 15px 11px;
|
|
1047
|
+
text-align: center;
|
|
1048
|
+
transition: all .15s;
|
|
1049
|
+
color: var(--text-2);
|
|
1050
|
+
user-select: none;
|
|
1051
|
+
border-radius: 6px;
|
|
1052
|
+
border: 1px solid var(--border-default, #E5E5E5);
|
|
758
1053
|
}
|
|
759
1054
|
.cg-item:hover{background:var(--accent-bg);border-color:var(--accent);color:var(--accent-txt);transform:translateY(-1px);box-shadow:0 2px 8px rgba(99,102,241,.15)}
|
|
760
1055
|
.cg-item:active{transform:translateY(0);box-shadow:none}
|
|
761
|
-
.cg-icon{
|
|
762
|
-
|
|
1056
|
+
.cg-icon{ margin-bottom: 6px;
|
|
1057
|
+
color: var(--content-default, #404040);
|
|
1058
|
+
font-family: Inter;
|
|
1059
|
+
font-size: var(--font-size-sm, 14px);
|
|
1060
|
+
font-style: normal;
|
|
1061
|
+
font-weight: 500;
|
|
1062
|
+
line-height: var(--font-leading-4, 16px);}
|
|
1063
|
+
.cg-name{ color: var(--content-subtle, #737373);
|
|
1064
|
+
font-family: Inter;
|
|
1065
|
+
font-size: var(--font-size-xs, 12px);
|
|
1066
|
+
font-style: normal;
|
|
1067
|
+
font-weight: 400;
|
|
1068
|
+
line-height: var(--font-leading-3, 12px);}
|
|
763
1069
|
|
|
764
1070
|
/* \u2500\u2500 Section list \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
765
1071
|
.sec-item{
|
|
@@ -768,8 +1074,12 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
768
1074
|
}
|
|
769
1075
|
.sec-item:hover{border-color:var(--accent);transform:translateY(-1px);box-shadow:0 4px 12px rgba(99,102,241,.12)}
|
|
770
1076
|
.sec-thumb{
|
|
771
|
-
background:var(--bg-sub);height:
|
|
772
|
-
justify-content:center;font-size:22px;border-bottom:1px solid var(--border)
|
|
1077
|
+
background:var(--bg-sub);height:auto;display:flex;align-items:center;
|
|
1078
|
+
justify-content:center;font-size:22px;border-bottom:1px solid var(--border);
|
|
1079
|
+
overflow:hidden;
|
|
1080
|
+
}
|
|
1081
|
+
.sec-thumb img{
|
|
1082
|
+
width:100%;height:100%;object-fit:cover;object-position:top center;display:block;
|
|
773
1083
|
}
|
|
774
1084
|
.sec-info{padding:7px 9px}
|
|
775
1085
|
.sec-name{font-size:11px;font-weight:600;color:var(--text)}
|
|
@@ -785,11 +1095,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
|
|
|
785
1095
|
#no-sel .ns-icon{font-size:32px;margin-bottom:10px;opacity:.4}
|
|
786
1096
|
|
|
787
1097
|
/* \u2500\u2500 Element info header \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
788
|
-
#el-info{padding:8px 12px;border-bottom:1px solid var(--border);background:var(--bg-sub);flex-shrink:0}
|
|
789
|
-
#el-info-tag{font-size:10px;font-weight:700;color:var(--text-3);text-transform:uppercase;letter-spacing:.05em;font-family:
|
|
790
|
-
#el-info-sel{font-size:10px;color:var(--accent-txt);font-family:
|
|
1098
|
+
#el-info{padding:8px 12px;border-bottom:1px solid var(--border);background:var(--bg-sub);flex-shrink:0;display:none;}
|
|
1099
|
+
#el-info-tag{font-size:10px;font-weight:700;color:var(--text-3);text-transform:uppercase;letter-spacing:.05em;font-family:var(--font-mono)}
|
|
1100
|
+
#el-info-sel{font-size:10px;color:var(--accent-txt);font-family:var(--font-mono);margin-top:2px;word-break:break-all;opacity:.8}
|
|
791
1101
|
|
|
792
1102
|
/* \u2500\u2500 Accordion \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
1103
|
+
#tab-design.rp-pane.active{
|
|
1104
|
+
display:flex;
|
|
1105
|
+
flex-direction:column;
|
|
1106
|
+
min-height:0;
|
|
1107
|
+
overflow-y:auto;
|
|
1108
|
+
overflow-x:hidden;
|
|
1109
|
+
}
|
|
1110
|
+
#rp-accordion.rp-accordion{
|
|
1111
|
+
flex:1;
|
|
1112
|
+
min-height:0;
|
|
1113
|
+
overflow-y:auto;
|
|
1114
|
+
overflow-x:hidden;
|
|
1115
|
+
}
|
|
1116
|
+
#rp-accordion.rp-accordion::-webkit-scrollbar{width:3px}
|
|
1117
|
+
#rp-accordion.rp-accordion::-webkit-scrollbar-thumb{background:#e2e8f0;border-radius:2px}
|
|
793
1118
|
.acc-section{border-bottom:1px solid var(--border-sub)}
|
|
794
1119
|
.acc-hd{
|
|
795
1120
|
display:flex;align-items:center;padding:11px 14px;cursor:pointer;
|
|
@@ -842,7 +1167,7 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
|
|
|
842
1167
|
.custom-css-close:hover{background:var(--bg-hover);color:var(--text)}
|
|
843
1168
|
#custom-css-modal-textarea{
|
|
844
1169
|
width:100%;min-height:360px;max-height:58vh;resize:vertical;border:none;outline:none;
|
|
845
|
-
font-family:
|
|
1170
|
+
font-family:var(--font-mono);
|
|
846
1171
|
font-size:12px;line-height:1.5;padding:12px;background:#0b1220;color:#e2e8f0
|
|
847
1172
|
}
|
|
848
1173
|
.custom-css-actions{
|
|
@@ -885,7 +1210,7 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
885
1210
|
.adv-section{padding:10px}
|
|
886
1211
|
.adv-row{margin-bottom:8px}
|
|
887
1212
|
.adv-key{font-size:10px;color:var(--text-3);margin-bottom:3px;font-weight:700;text-transform:uppercase;letter-spacing:.05em}
|
|
888
|
-
.adv-val{font-size:11px;color:var(--text-2);word-break:break-all;background:var(--bg-sub);padding:5px 7px;border-radius:5px;font-family:
|
|
1213
|
+
.adv-val{font-size:11px;color:var(--text-2);word-break:break-all;background:var(--bg-sub);padding:5px 7px;border-radius:5px;font-family:var(--font-mono);border:1px solid var(--border)}
|
|
889
1214
|
|
|
890
1215
|
/* \u2500\u2500 Selected element ring + drag affordance \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
891
1216
|
/* Selection chrome is injected into the iframe (see injectIframeSelectionStyles); rules here are fallback only */
|
|
@@ -918,15 +1243,48 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
918
1243
|
}
|
|
919
1244
|
.img-add:hover{border-color:var(--accent);color:var(--accent-txt);background:var(--accent-bg)}
|
|
920
1245
|
|
|
1246
|
+
/* \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 */
|
|
1247
|
+
.video-preview{
|
|
1248
|
+
width:100%;height:120px;object-fit:contain;border:1px solid var(--border);
|
|
1249
|
+
border-radius:6px;background:#000;margin-bottom:8px;display:block
|
|
1250
|
+
}
|
|
1251
|
+
.embed-preview{
|
|
1252
|
+
width:100%;aspect-ratio:16/9;border:1px solid var(--border);
|
|
1253
|
+
border-radius:6px;background:#000;margin-bottom:8px;display:block;border:none
|
|
1254
|
+
}
|
|
1255
|
+
|
|
921
1256
|
/* \u2500\u2500 Right panel main tabs (Design / States / History) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
922
|
-
#main-tabs{
|
|
1257
|
+
#main-tabs{
|
|
1258
|
+
display:flex;
|
|
1259
|
+
align-items:center;
|
|
1260
|
+
gap:6px;
|
|
1261
|
+
margin:12px 16px 8px;
|
|
1262
|
+
padding:4px 6px;
|
|
1263
|
+
border-radius:6px;
|
|
1264
|
+
background:var(--base-soft-2,#F0F0F0);
|
|
1265
|
+
flex-shrink:0;
|
|
1266
|
+
}
|
|
923
1267
|
.main-tab{
|
|
924
|
-
flex:1;
|
|
925
|
-
|
|
926
|
-
|
|
1268
|
+
flex:1;
|
|
1269
|
+
padding:4px 10px;
|
|
1270
|
+
text-align:center;
|
|
1271
|
+
font-size:var(--font-size-sm,14px);
|
|
1272
|
+
font-weight:500;
|
|
1273
|
+
line-height:1.15;
|
|
1274
|
+
color:#404040;
|
|
1275
|
+
white-space:nowrap;
|
|
1276
|
+
cursor:pointer;
|
|
1277
|
+
border:none;
|
|
1278
|
+
background:transparent;
|
|
1279
|
+
transition:all .15s;
|
|
1280
|
+
font-family:inherit;
|
|
927
1281
|
}
|
|
928
1282
|
.main-tab:hover{color:var(--text-2)}
|
|
929
|
-
.main-tab.active{
|
|
1283
|
+
.main-tab.active{
|
|
1284
|
+
border-radius:4px;
|
|
1285
|
+
background:var(--bg-interactive-default,#FFF);
|
|
1286
|
+
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);
|
|
1287
|
+
}
|
|
930
1288
|
.rp-pane{flex:1;overflow-y:auto;overflow-x:hidden;min-width:0;display:none}
|
|
931
1289
|
.rp-pane.active{display:block}
|
|
932
1290
|
|
|
@@ -935,13 +1293,13 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
935
1293
|
.states-empty i{font-size:30px;display:block;margin-bottom:10px;opacity:.3}
|
|
936
1294
|
.state-group{border-bottom:1px solid var(--border-sub)}
|
|
937
1295
|
.state-group-sel{
|
|
938
|
-
padding:8px 12px 3px;font-size:10px;font-family:
|
|
1296
|
+
padding:8px 12px 3px;font-size:10px;font-family:var(--font-mono);
|
|
939
1297
|
color:var(--text-3);font-weight:700;word-break:break-all;letter-spacing:-.01em
|
|
940
1298
|
}
|
|
941
1299
|
.state-item{display:flex;align-items:center;padding:4px 10px 4px 18px;gap:6px}
|
|
942
1300
|
.state-item-label{flex:1;font-size:11px;color:var(--text-2)}
|
|
943
1301
|
.state-item-val{
|
|
944
|
-
font-size:10px;color:var(--accent-txt);font-family:
|
|
1302
|
+
font-size:10px;color:var(--accent-txt);font-family:var(--font-mono);
|
|
945
1303
|
max-width:68px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
|
|
946
1304
|
background:var(--accent-bg);padding:1px 5px;border-radius:3px
|
|
947
1305
|
}
|
|
@@ -1036,9 +1394,56 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1036
1394
|
.history-remove{
|
|
1037
1395
|
margin-top:2px;
|
|
1038
1396
|
}
|
|
1397
|
+
|
|
1398
|
+
/* \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 */
|
|
1399
|
+
#ve-min-screen-notice{
|
|
1400
|
+
display:none;
|
|
1401
|
+
position:fixed;
|
|
1402
|
+
inset:0;
|
|
1403
|
+
z-index:99999;
|
|
1404
|
+
flex-direction:column;
|
|
1405
|
+
align-items:center;
|
|
1406
|
+
justify-content:center;
|
|
1407
|
+
gap:12px;
|
|
1408
|
+
padding:24px;
|
|
1409
|
+
text-align:center;
|
|
1410
|
+
background:#f1f5f9;
|
|
1411
|
+
color:#404040;
|
|
1412
|
+
}
|
|
1413
|
+
#ve-min-screen-notice .ve-min-screen-icon{
|
|
1414
|
+
font-size:40px;
|
|
1415
|
+
color:#737373;
|
|
1416
|
+
line-height:1;
|
|
1417
|
+
}
|
|
1418
|
+
#ve-min-screen-notice .ve-min-screen-title{
|
|
1419
|
+
font-size:18px;
|
|
1420
|
+
font-weight:600;
|
|
1421
|
+
color:#262626;
|
|
1422
|
+
max-width:420px;
|
|
1423
|
+
}
|
|
1424
|
+
#ve-min-screen-notice .ve-min-screen-desc{
|
|
1425
|
+
font-size:14px;
|
|
1426
|
+
color:#737373;
|
|
1427
|
+
max-width:420px;
|
|
1428
|
+
line-height:1.5;
|
|
1429
|
+
}
|
|
1430
|
+
@media (max-width:1100px){
|
|
1431
|
+
#app,
|
|
1432
|
+
#custom-css-modal{
|
|
1433
|
+
display:none!important;
|
|
1434
|
+
}
|
|
1435
|
+
#ve-min-screen-notice{
|
|
1436
|
+
display:flex;
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1039
1439
|
</style>
|
|
1040
1440
|
</head>
|
|
1041
1441
|
<body class="mode-editor">
|
|
1442
|
+
<div id="ve-min-screen-notice" aria-live="polite">
|
|
1443
|
+
<div class="ve-min-screen-icon"><i class="bi bi-display"></i></div>
|
|
1444
|
+
<div class="ve-min-screen-title">Please switch to greater or bigger screen to use Visual Editor</div>
|
|
1445
|
+
<div class="ve-min-screen-desc">The Visual Editor requires a screen width of at least 1100px.</div>
|
|
1446
|
+
</div>
|
|
1042
1447
|
<div id="app">
|
|
1043
1448
|
<!-- \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 -->
|
|
1044
1449
|
<div id="toolbar">
|
|
@@ -1069,7 +1474,17 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1069
1474
|
<div id="dev-more-menu" class="tb-dev-menu" aria-hidden="true">
|
|
1070
1475
|
<div class="row row-zoom">
|
|
1071
1476
|
<label for="dev-zoom-level">Zoom</label>
|
|
1072
|
-
<
|
|
1477
|
+
<div class="zoom-controls">
|
|
1478
|
+
<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">
|
|
1479
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true">
|
|
1480
|
+
<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"/>
|
|
1481
|
+
<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"/>
|
|
1482
|
+
<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"/>
|
|
1483
|
+
<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"/>
|
|
1484
|
+
</svg>
|
|
1485
|
+
</button>
|
|
1486
|
+
<input id="dev-zoom-level" type="number" min="25" max="200" step="5" value="100" />
|
|
1487
|
+
</div>
|
|
1073
1488
|
</div>
|
|
1074
1489
|
<div class="row row-split row-width height-width-row">
|
|
1075
1490
|
<div class="row" style="margin:0">
|
|
@@ -1094,9 +1509,6 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1094
1509
|
<button type="button" class="vp-preset-btn" data-preset="iphone-7">iPhone 7</button>
|
|
1095
1510
|
<button type="button" class="vp-preset-btn" data-preset="responsive">Responsive</button>
|
|
1096
1511
|
</div>
|
|
1097
|
-
<div class="ft">
|
|
1098
|
-
<button type="button" class="apply-btn" id="dev-apply-btn">Apply</button>
|
|
1099
|
-
</div>
|
|
1100
1512
|
</div>
|
|
1101
1513
|
</div>
|
|
1102
1514
|
<button class="tb-dk-btn" id="btn-undo" title="Undo (\u2318Z)"><i class="bi bi-arrow-counterclockwise"></i></button>
|
|
@@ -1124,15 +1536,16 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1124
1536
|
<span class="tb-save-txt"></span>
|
|
1125
1537
|
<span id="tb-save-time" class="tb-save-time"></span>
|
|
1126
1538
|
</div>
|
|
1539
|
+
<button class="tb-fin-btn" id="btn-save">Save Changes</button>
|
|
1127
1540
|
<div class="tb-dev-3btns">
|
|
1128
1541
|
<button class="tb-dk-btn active" id="btn-mode-editor" onclick="setMode('editor')" title="Edit mode \u2014 click elements to edit"><i class="bi bi-pencil"></i></button>
|
|
1129
|
-
<button class="tb-dk-btn" id="btn-mode-nav" onclick="setMode('navigate')" title="Navigate mode \u2014 interact with page normally"><i class="bi bi-
|
|
1542
|
+
<button class="tb-dk-btn" id="btn-mode-nav" onclick="setMode('navigate')" title="Navigate mode \u2014 interact with page normally"><i class="bi bi-cursor"></i></button>
|
|
1130
1543
|
<button class="tb-dk-btn" title="Comments"><i class="bi bi-chat-dots"></i></button>
|
|
1131
1544
|
</div>
|
|
1132
|
-
<button class="tb-sim-btn" id="btn-simulate" onclick="simulateExperiment()"
|
|
1133
|
-
|
|
1545
|
+
<button class="tb-sim-btn" id="btn-simulate" onclick="simulateExperiment()">See Preview</button>
|
|
1546
|
+
|
|
1134
1547
|
<!-- btn-close: kept for JS event listener -->
|
|
1135
|
-
<button class="tb-fin-btn" id="btn-close">
|
|
1548
|
+
<button class="tb-fin-btn" id="btn-close">Exit Editor</button>
|
|
1136
1549
|
</div>
|
|
1137
1550
|
|
|
1138
1551
|
<!-- url-bar: hidden, kept for JS compatibility -->
|
|
@@ -1170,22 +1583,28 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1170
1583
|
|
|
1171
1584
|
<!-- Elements -->
|
|
1172
1585
|
<div class="lp-sec lp-sec-no-border">
|
|
1173
|
-
<div class="lp-sec-hd">
|
|
1174
|
-
<span class="lp-sec-hd-left">Elements <i style="display:none" class="bi bi-info-circle lp-info-icon" title="Page elements"></i></span>
|
|
1175
|
-
<button class="lp-add-btn" id="btn-add-element" title="Add element">+ Add</button>
|
|
1176
|
-
</div>
|
|
1177
|
-
|
|
1178
1586
|
<!-- Search (hidden, kept for JS) -->
|
|
1179
|
-
<div>
|
|
1180
|
-
<
|
|
1587
|
+
<div class="lp-search-container">
|
|
1588
|
+
<div class="lp-search-field">
|
|
1589
|
+
<span class="lp-search-icon" aria-hidden="true">
|
|
1590
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
|
|
1591
|
+
<path d="M11.333 11.3333L13.9997 13.9999" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
|
1592
|
+
<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"/>
|
|
1593
|
+
</svg>
|
|
1594
|
+
</span>
|
|
1595
|
+
<input type="search" id="comp-search" placeholder="Search" autocomplete="off">
|
|
1596
|
+
</div>
|
|
1181
1597
|
</div>
|
|
1182
1598
|
|
|
1183
1599
|
|
|
1184
1600
|
<!-- Tabs (hidden, kept for JS) -->
|
|
1185
|
-
<div class="lp-tabs"
|
|
1186
|
-
<div class="lp-
|
|
1601
|
+
<div class="lp-tabs-container">
|
|
1602
|
+
<div class="lp-tabs">
|
|
1603
|
+
<div class="lp-tab active" onclick="switchLeftTab('elements')">Elements</div>
|
|
1187
1604
|
<div class="lp-tab" onclick="switchLeftTab('dom-tree')">DOM Tree</div>
|
|
1188
1605
|
</div>
|
|
1606
|
+
<button class="lp-add-btn" id="btn-add-element" title="Add element">+ Add</button>
|
|
1607
|
+
</div>
|
|
1189
1608
|
|
|
1190
1609
|
</div>
|
|
1191
1610
|
|
|
@@ -1214,11 +1633,11 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1214
1633
|
|
|
1215
1634
|
<!-- Floating toolbar for selected element (positioned over iframe) -->
|
|
1216
1635
|
<div id="selection-floater" aria-label="Selection actions">
|
|
1636
|
+
<button type="button" class="sf-btn" id="sf-add" title="Add element"><i class="bi bi-plus-lg"></i></button>
|
|
1637
|
+
<span class="sf-sep"></span>
|
|
1217
1638
|
<button type="button" class="sf-btn" id="sf-move-up" title="Move up"><i class="bi bi-arrow-up"></i></button>
|
|
1218
1639
|
<button type="button" class="sf-btn" id="sf-move-down" title="Move down"><i class="bi bi-arrow-down"></i></button>
|
|
1219
1640
|
<span class="sf-sep"></span>
|
|
1220
|
-
<button type="button" class="sf-btn" id="sf-resize" disabled title="Resize (coming soon)"><i class="bi bi-arrows-angle-expand"></i></button>
|
|
1221
|
-
<button type="button" class="sf-btn" id="sf-rotate" disabled title="Rotate (coming soon)"><i class="bi bi-arrow-repeat"></i></button>
|
|
1222
1641
|
<button type="button" class="sf-btn" id="sf-dup" title="Duplicate"><i class="bi bi-files"></i></button>
|
|
1223
1642
|
<button type="button" class="sf-btn" id="sf-hide" title="Hide"><i class="bi bi-eye-slash"></i></button>
|
|
1224
1643
|
<button type="button" class="sf-btn" id="sf-del" title="Delete"><i class="bi bi-trash"></i></button>
|
|
@@ -1242,15 +1661,17 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1242
1661
|
|
|
1243
1662
|
<!-- Right panel -->
|
|
1244
1663
|
<div id="right-panel">
|
|
1245
|
-
<div id="section-components-panel"
|
|
1664
|
+
<div id="section-components-panel">
|
|
1246
1665
|
<!-- Left-tab controls moved here -->
|
|
1247
|
-
<div class="section-components-tabs">
|
|
1248
|
-
<div class="lp-
|
|
1249
|
-
|
|
1250
|
-
|
|
1666
|
+
<div class="lp-tabs-container section-components-tabs-container">
|
|
1667
|
+
<div class="lp-tabs">
|
|
1668
|
+
<div class="lp-tab active" onclick="switchSectionComponentsTab('components')">Components</div>
|
|
1669
|
+
<div class="lp-tab" onclick="switchSectionComponentsTab('sections')">Sections</div>
|
|
1670
|
+
</div>
|
|
1671
|
+
<div class="lp-tab close-section-components-panel collapsed" onclick="toggleSectionComponentsBody()" title="Toggle components list"><i class="bi bi-chevron-down"></i></div>
|
|
1251
1672
|
</div>
|
|
1252
|
-
<div class="lp-body">
|
|
1253
|
-
<div id="tab-components" class="tab-pane"></div>
|
|
1673
|
+
<div class="lp-body collapsed">
|
|
1674
|
+
<div id="tab-components" class="tab-pane active"></div>
|
|
1254
1675
|
<div id="tab-sections" class="tab-pane"></div>
|
|
1255
1676
|
</div>
|
|
1256
1677
|
</div>
|
|
@@ -1262,7 +1683,7 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1262
1683
|
<!-- \u2500\u2500 3 main tabs \u2500\u2500 -->
|
|
1263
1684
|
<div id="main-tabs">
|
|
1264
1685
|
<button class="main-tab active" onclick="switchMainTab('design')">Design</button>
|
|
1265
|
-
<button class="main-tab" onclick="switchMainTab('states')">States</button>
|
|
1686
|
+
<button class="main-tab" style="display:none" onclick="switchMainTab('states')">States</button>
|
|
1266
1687
|
<button class="main-tab" onclick="switchMainTab('history')">History</button>
|
|
1267
1688
|
</div>
|
|
1268
1689
|
|
|
@@ -1272,15 +1693,33 @@ select.pr-inp{cursor:pointer;background:#fff}
|
|
|
1272
1693
|
<div class="ns-icon"><i class="bi bi-cursor-text"></i></div>
|
|
1273
1694
|
Click any element on the page to edit its properties
|
|
1274
1695
|
</div>
|
|
1275
|
-
<div id="rp-accordion" style="display:none">
|
|
1696
|
+
<div id="rp-accordion" class="rp-accordion" style="display:none">
|
|
1276
1697
|
|
|
1277
1698
|
<!-- Image section \u2014 only shown when an <img> is selected -->
|
|
1278
|
-
<div class="acc-section
|
|
1699
|
+
<div class="acc-section" id="acc-image" style="display:none">
|
|
1279
1700
|
<div class="acc-hd" onclick="toggleAcc('image')">Image<i class="bi bi-chevron-right acc-arrow"></i></div>
|
|
1280
1701
|
<div class="acc-body" id="acc-body-image"></div>
|
|
1281
1702
|
</div>
|
|
1282
1703
|
|
|
1283
|
-
|
|
1704
|
+
<!-- Video section \u2014 only shown when a <video> is selected -->
|
|
1705
|
+
<div class="acc-section" id="acc-video" style="display:none">
|
|
1706
|
+
<div class="acc-hd" onclick="toggleAcc('video')">Video<i class="bi bi-chevron-right acc-arrow"></i></div>
|
|
1707
|
+
<div class="acc-body" id="acc-body-video"></div>
|
|
1708
|
+
</div>
|
|
1709
|
+
|
|
1710
|
+
<!-- YouTube section \u2014 only shown when a YouTube iframe is selected -->
|
|
1711
|
+
<div class="acc-section" id="acc-youtube" style="display:none">
|
|
1712
|
+
<div class="acc-hd" onclick="toggleAcc('youtube')">YouTube Video<i class="bi bi-chevron-right acc-arrow"></i></div>
|
|
1713
|
+
<div class="acc-body" id="acc-body-youtube"></div>
|
|
1714
|
+
</div>
|
|
1715
|
+
|
|
1716
|
+
<!-- Vimeo section \u2014 only shown when a Vimeo iframe is selected -->
|
|
1717
|
+
<div class="acc-section" id="acc-vimeo" style="display:none">
|
|
1718
|
+
<div class="acc-hd" onclick="toggleAcc('vimeo')">Vimeo Video<i class="bi bi-chevron-right acc-arrow"></i></div>
|
|
1719
|
+
<div class="acc-body" id="acc-body-vimeo"></div>
|
|
1720
|
+
</div>
|
|
1721
|
+
|
|
1722
|
+
<div class="acc-section" id="acc-content">
|
|
1284
1723
|
<div class="acc-hd" onclick="toggleAcc('content')">HTML Content<i class="bi bi-chevron-right acc-arrow"></i></div>
|
|
1285
1724
|
<div class="acc-body" id="acc-body-content"></div>
|
|
1286
1725
|
</div>
|
|
@@ -1452,28 +1891,101 @@ if (window.Vvveb && window.Vvveb.Components) {
|
|
|
1452
1891
|
|
|
1453
1892
|
// \u2500\u2500 CRO definitions + Base components \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
1454
1893
|
var CRO_SECTIONS = ${sectionsJson};
|
|
1894
|
+
var CRO_SECTION_IMAGE_ROUTE = ${JSON.stringify(CRO_SECTION_IMAGE_ROUTE)};
|
|
1895
|
+
|
|
1896
|
+
function renderCroSectionThumb(sec) {
|
|
1897
|
+
if (sec && sec.image) {
|
|
1898
|
+
return '<img src="' + CRO_SECTION_IMAGE_ROUTE + sec.image + '" alt="' + esc(sec.name || '') + '" loading="lazy">';
|
|
1899
|
+
}
|
|
1900
|
+
return sec && sec.icon ? sec.icon : '\u{1F4E6}';
|
|
1901
|
+
}
|
|
1455
1902
|
|
|
1456
1903
|
var BASE_COMPONENTS = [
|
|
1457
|
-
{ name:'Heading', icon:'bi-type-h1', html:'<h2>Your Heading</h2>' },
|
|
1458
|
-
{ name:'Paragraph', icon:'bi-paragraph', html:'<p>Your text here. Click to edit.</p>' },
|
|
1459
|
-
{ name:'Image', icon:'bi-image', html:'<img src="https://placehold.co/600x300/1a1a2e/a78bfa?text=Image" alt="Image" style="max-width:100
|
|
1460
|
-
{ name:'Button', icon:'bi-hand-index', html:'<button
|
|
1461
|
-
{ name:'Link', icon:'bi-link-45deg', html:'<a href="#">Link text</a>' },
|
|
1462
|
-
{ name:'Divider', icon:'bi-dash-lg', html:'<hr>' },
|
|
1463
|
-
{ name:'List', icon:'bi-list-ul', html:'<ul><li>Item 1</li><li>Item 2</li><li>Item 3</li></ul>' },
|
|
1464
|
-
{ name:'Video', icon:'bi-play-circle', html:'<video controls style="max-width:100
|
|
1465
|
-
{ name:'
|
|
1466
|
-
{ name:'
|
|
1467
|
-
{ name:'
|
|
1468
|
-
{ name:'
|
|
1469
|
-
{ name:'
|
|
1470
|
-
{ name:'
|
|
1471
|
-
{ name:'
|
|
1472
|
-
{ name:'
|
|
1473
|
-
{ name:'
|
|
1474
|
-
{ name:'
|
|
1904
|
+
{ 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>' },
|
|
1905
|
+
{ 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>' },
|
|
1906
|
+
{ 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">' },
|
|
1907
|
+
{ 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>' },
|
|
1908
|
+
{ 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>' },
|
|
1909
|
+
{ name:'Divider', icon:'bi-dash-lg', defaultAccSection:'background', html:'<hr style="margin:16px 0;border:none;border-top:1px solid #e2e8f0">' },
|
|
1910
|
+
{ 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>' },
|
|
1911
|
+
{ 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>' },
|
|
1912
|
+
{ 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>' },
|
|
1913
|
+
{ 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>' },
|
|
1914
|
+
{ 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>' },
|
|
1915
|
+
{ 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">' },
|
|
1916
|
+
{ 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>' },
|
|
1917
|
+
{ 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>' },
|
|
1918
|
+
{ 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>' },
|
|
1919
|
+
{ 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>' },
|
|
1920
|
+
{ 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>' },
|
|
1921
|
+
{ 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>' },
|
|
1922
|
+
{ name:'2 Cols', icon:'bi-layout-split', defaultAccSection:'spacing', html:'<div style="display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px;width:100%;box-sizing:border-box"><div style="padding:16px;background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px;min-height:80px;box-sizing:border-box"><p style="margin:0">Left column</p></div><div style="padding:16px;background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px;min-height:80px;box-sizing:border-box"><p style="margin:0">Right column</p></div></div>' },
|
|
1475
1923
|
];
|
|
1476
1924
|
|
|
1925
|
+
var baseComponentAccRegistry = null;
|
|
1926
|
+
|
|
1927
|
+
function buildBaseComponentAccRegistry() {
|
|
1928
|
+
if (baseComponentAccRegistry) return baseComponentAccRegistry;
|
|
1929
|
+
var matchers = [];
|
|
1930
|
+
var tagFallback = {};
|
|
1931
|
+
|
|
1932
|
+
BASE_COMPONENTS.forEach(function(comp) {
|
|
1933
|
+
var section = comp.defaultAccSection || 'content';
|
|
1934
|
+
var html = String(comp.html || '').trim();
|
|
1935
|
+
if (!html) return;
|
|
1936
|
+
var tagMatch = html.match(/^<([a-z0-9-]+)/i);
|
|
1937
|
+
if (!tagMatch) return;
|
|
1938
|
+
var rootTag = tagMatch[1].toLowerCase();
|
|
1939
|
+
var matcher = { tag: rootTag, section: section };
|
|
1940
|
+
|
|
1941
|
+
if (rootTag === 'div') {
|
|
1942
|
+
if (html.indexOf('role="alert"') >= 0) matcher.role = 'alert';
|
|
1943
|
+
else if (html.indexOf('repeat(2') >= 0) matcher.gridCols = 2;
|
|
1944
|
+
else if (html.indexOf('repeat(3') >= 0) matcher.gridCols = 3;
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1947
|
+
if (matcher.role || matcher.gridCols) matchers.push(matcher);
|
|
1948
|
+
else if (tagFallback[rootTag] === undefined) tagFallback[rootTag] = section;
|
|
1949
|
+
});
|
|
1950
|
+
|
|
1951
|
+
['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].forEach(function(tag) {
|
|
1952
|
+
if (tagFallback[tag] === undefined) tagFallback[tag] = tagFallback.h2 || 'content';
|
|
1953
|
+
});
|
|
1954
|
+
if (tagFallback.ol === undefined) tagFallback.ol = tagFallback.ul || 'content';
|
|
1955
|
+
|
|
1956
|
+
baseComponentAccRegistry = { matchers: matchers, tagFallback: tagFallback };
|
|
1957
|
+
return baseComponentAccRegistry;
|
|
1958
|
+
}
|
|
1959
|
+
|
|
1960
|
+
function matchesBaseComponentAccMatcher(el, matcher) {
|
|
1961
|
+
if (!el || !matcher || el.tagName.toLowerCase() !== matcher.tag) return false;
|
|
1962
|
+
if (matcher.role) return el.getAttribute('role') === matcher.role;
|
|
1963
|
+
if (matcher.gridCols) {
|
|
1964
|
+
var style = (el.getAttribute('style') || '').toLowerCase();
|
|
1965
|
+
return style.indexOf('grid-template-columns') >= 0 &&
|
|
1966
|
+
style.indexOf('repeat(' + matcher.gridCols) >= 0;
|
|
1967
|
+
}
|
|
1968
|
+
return true;
|
|
1969
|
+
}
|
|
1970
|
+
|
|
1971
|
+
function getTypeDefaultAccSection(el) {
|
|
1972
|
+
if (!el) return 'content';
|
|
1973
|
+
if (isYoutubeVideoElement(el)) return 'youtube';
|
|
1974
|
+
if (isVimeoVideoElement(el)) return 'vimeo';
|
|
1975
|
+
|
|
1976
|
+
var registry = buildBaseComponentAccRegistry();
|
|
1977
|
+
var i;
|
|
1978
|
+
for (i = 0; i < registry.matchers.length; i++) {
|
|
1979
|
+
if (matchesBaseComponentAccMatcher(el, registry.matchers[i])) {
|
|
1980
|
+
return registry.matchers[i].section;
|
|
1981
|
+
}
|
|
1982
|
+
}
|
|
1983
|
+
|
|
1984
|
+
var tag = el.tagName.toLowerCase();
|
|
1985
|
+
if (registry.tagFallback[tag]) return registry.tagFallback[tag];
|
|
1986
|
+
return 'content';
|
|
1987
|
+
}
|
|
1988
|
+
|
|
1477
1989
|
// \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
|
|
1478
1990
|
var CHANNEL = 'vvveb-bridge';
|
|
1479
1991
|
|
|
@@ -1625,7 +2137,7 @@ var leftPanelCollapsed = false;
|
|
|
1625
2137
|
var viewportPreset = 'desktop';
|
|
1626
2138
|
var viewportWidth = 1440;
|
|
1627
2139
|
var viewportHeight = 1024;
|
|
1628
|
-
var viewportZoom =
|
|
2140
|
+
var viewportZoom = null;
|
|
1629
2141
|
var selectedEl = null;
|
|
1630
2142
|
/** Stable selector fingerprint for resilient selection recovery after DOM churn. */
|
|
1631
2143
|
var selectedElFingerprint = '';
|
|
@@ -1645,6 +2157,7 @@ var iframeSyncRetryTimer = null;
|
|
|
1645
2157
|
var iframeSyncAttempts = 0;
|
|
1646
2158
|
var selectionScrollWin = null;
|
|
1647
2159
|
var selectionResizeBound = false;
|
|
2160
|
+
var selectionPanelScrollBound = false;
|
|
1648
2161
|
var clickAttachDoc = null;
|
|
1649
2162
|
var hoverAttachDoc = null;
|
|
1650
2163
|
var changeObserver = null;
|
|
@@ -1896,16 +2409,22 @@ function clampViewportNumber(v, fallback, min, max) {
|
|
|
1896
2409
|
|
|
1897
2410
|
function getViewportFitZoom() {
|
|
1898
2411
|
var panel = document.getElementById('iframe-panel');
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
2412
|
+
if (!panel || !viewportWidth || viewportWidth <= 0 || !viewportHeight || viewportHeight <= 0) return 1;
|
|
2413
|
+
var availW = Math.max(260, panel.clientWidth);
|
|
2414
|
+
var availH = Math.max(200, panel.clientHeight);
|
|
2415
|
+
return Math.min(1, availW / viewportWidth, availH / viewportHeight);
|
|
1902
2416
|
}
|
|
1903
2417
|
|
|
1904
2418
|
function getAppliedViewportZoom() {
|
|
1905
|
-
var
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
return Math.min(
|
|
2419
|
+
var fit = getViewportFitZoom();
|
|
2420
|
+
var z = viewportZoom != null ? Number(viewportZoom) : fit;
|
|
2421
|
+
if (!Number.isFinite(z) || z <= 0) z = fit;
|
|
2422
|
+
return Math.max(0.25, Math.min(2, z));
|
|
2423
|
+
}
|
|
2424
|
+
|
|
2425
|
+
function resetViewportZoomToFit() {
|
|
2426
|
+
viewportZoom = null;
|
|
2427
|
+
applyViewportFrame();
|
|
1909
2428
|
}
|
|
1910
2429
|
|
|
1911
2430
|
function updateViewportLabel() {
|
|
@@ -1926,20 +2445,28 @@ function syncViewportMenuControls() {
|
|
|
1926
2445
|
presetButtons[i].classList.toggle('active', key === viewportPreset);
|
|
1927
2446
|
}
|
|
1928
2447
|
}
|
|
1929
|
-
if (widthInp) widthInp.value = String(viewportWidth);
|
|
1930
|
-
if (heightInp) heightInp.value = String(viewportHeight);
|
|
2448
|
+
if (widthInp && document.activeElement !== widthInp) widthInp.value = String(viewportWidth);
|
|
2449
|
+
if (heightInp && document.activeElement !== heightInp) heightInp.value = String(viewportHeight);
|
|
1931
2450
|
if (zoomInp) zoomInp.value = String(Math.round(getAppliedViewportZoom() * 100));
|
|
1932
2451
|
}
|
|
1933
2452
|
|
|
1934
2453
|
function applyViewportFrame() {
|
|
1935
2454
|
var frame = document.getElementById('device-frame');
|
|
1936
2455
|
var iframe = document.getElementById('iframeId');
|
|
2456
|
+
var panel = document.getElementById('iframe-panel');
|
|
1937
2457
|
if (!frame) return;
|
|
1938
2458
|
frame.className = currentDevice;
|
|
1939
2459
|
frame.style.width = viewportWidth + 'px';
|
|
1940
2460
|
frame.style.height = viewportHeight + 'px';
|
|
1941
2461
|
frame.style.maxWidth = 'none';
|
|
1942
|
-
|
|
2462
|
+
var zoom = getAppliedViewportZoom();
|
|
2463
|
+
var fit = getViewportFitZoom();
|
|
2464
|
+
frame.style.zoom = String(zoom);
|
|
2465
|
+
if (panel) {
|
|
2466
|
+
var zoomedIn = zoom > fit + 0.001;
|
|
2467
|
+
panel.style.overflow = zoomedIn ? 'auto' : 'hidden';
|
|
2468
|
+
panel.style.alignItems = zoomedIn ? 'flex-start' : 'center';
|
|
2469
|
+
}
|
|
1943
2470
|
if (iframe) {
|
|
1944
2471
|
iframe.style.height = viewportHeight + 'px';
|
|
1945
2472
|
iframe.style.minHeight = viewportHeight + 'px';
|
|
@@ -1956,6 +2483,7 @@ function setViewportPreset(presetKey) {
|
|
|
1956
2483
|
viewportWidth = preset.width;
|
|
1957
2484
|
viewportHeight = preset.height;
|
|
1958
2485
|
currentDevice = preset.device || 'desktop';
|
|
2486
|
+
viewportZoom = null;
|
|
1959
2487
|
['desktop','tablet','mobile'].forEach(function(d) {
|
|
1960
2488
|
document.getElementById('dev-' + d).classList.toggle('active', d === currentDevice);
|
|
1961
2489
|
});
|
|
@@ -1968,20 +2496,26 @@ function setDevice(device) {
|
|
|
1968
2496
|
var preset = DEVICE_PRESETS[device] || DEVICE_PRESETS.desktop;
|
|
1969
2497
|
viewportWidth = preset.width;
|
|
1970
2498
|
viewportHeight = preset.height;
|
|
2499
|
+
viewportZoom = null;
|
|
1971
2500
|
['desktop','tablet','mobile'].forEach(function(d) {
|
|
1972
2501
|
document.getElementById('dev-' + d).classList.toggle('active', d === device);
|
|
1973
2502
|
});
|
|
1974
2503
|
applyViewportFrame();
|
|
1975
2504
|
}
|
|
1976
2505
|
|
|
1977
|
-
function setViewportCustomFromInputs() {
|
|
2506
|
+
function setViewportCustomFromInputs(opts) {
|
|
2507
|
+
opts = opts || {};
|
|
1978
2508
|
var widthInp = document.getElementById('dev-custom-width');
|
|
1979
2509
|
var heightInp = document.getElementById('dev-custom-height');
|
|
1980
|
-
var
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
2510
|
+
var rawW = widthInp ? widthInp.value : '';
|
|
2511
|
+
var rawH = heightInp ? heightInp.value : '';
|
|
2512
|
+
if (!opts.force) {
|
|
2513
|
+
if (widthInp && document.activeElement === widthInp && rawW === '') return;
|
|
2514
|
+
if (heightInp && document.activeElement === heightInp && rawH === '') return;
|
|
2515
|
+
}
|
|
2516
|
+
viewportWidth = clampViewportNumber(rawW, viewportWidth, 240, 3840);
|
|
2517
|
+
viewportHeight = clampViewportNumber(rawH, viewportHeight, 320, 3840);
|
|
2518
|
+
viewportZoom = null;
|
|
1985
2519
|
viewportPreset = 'custom';
|
|
1986
2520
|
currentDevice = viewportWidth <= 480 ? 'mobile' : (viewportWidth <= 1024 ? 'tablet' : 'desktop');
|
|
1987
2521
|
['desktop','tablet','mobile'].forEach(function(d) {
|
|
@@ -1990,6 +2524,22 @@ function setViewportCustomFromInputs() {
|
|
|
1990
2524
|
applyViewportFrame();
|
|
1991
2525
|
}
|
|
1992
2526
|
|
|
2527
|
+
var customViewportApplyTimer = null;
|
|
2528
|
+
function scheduleCustomViewportApply() {
|
|
2529
|
+
if (customViewportApplyTimer) clearTimeout(customViewportApplyTimer);
|
|
2530
|
+
customViewportApplyTimer = setTimeout(function() {
|
|
2531
|
+
customViewportApplyTimer = null;
|
|
2532
|
+
setViewportCustomFromInputs();
|
|
2533
|
+
}, 300);
|
|
2534
|
+
}
|
|
2535
|
+
function applyCustomViewportNow() {
|
|
2536
|
+
if (customViewportApplyTimer) {
|
|
2537
|
+
clearTimeout(customViewportApplyTimer);
|
|
2538
|
+
customViewportApplyTimer = null;
|
|
2539
|
+
}
|
|
2540
|
+
setViewportCustomFromInputs({ force: true });
|
|
2541
|
+
}
|
|
2542
|
+
|
|
1993
2543
|
function closeViewportMenu() {
|
|
1994
2544
|
var menu = document.getElementById('dev-more-menu');
|
|
1995
2545
|
if (!menu) return;
|
|
@@ -2010,8 +2560,10 @@ function bindViewportControls() {
|
|
|
2010
2560
|
var menu = document.getElementById('dev-more-menu');
|
|
2011
2561
|
var leftPanelToggleLabel = document.getElementById('left-panel-toggle-label');
|
|
2012
2562
|
var presetButtons = document.querySelectorAll('#dev-preset-list .vp-preset-btn');
|
|
2013
|
-
var
|
|
2563
|
+
var widthInp = document.getElementById('dev-custom-width');
|
|
2564
|
+
var heightInp = document.getElementById('dev-custom-height');
|
|
2014
2565
|
var zoomInp = document.getElementById('dev-zoom-level');
|
|
2566
|
+
var zoomFitBtn = document.getElementById('dev-zoom-fit-btn');
|
|
2015
2567
|
var viewportBtn = document.querySelector('.tb-viewport');
|
|
2016
2568
|
function updateLeftPanelToggleLabel() {
|
|
2017
2569
|
if (!leftPanelToggleLabel) return;
|
|
@@ -2041,11 +2593,21 @@ function bindViewportControls() {
|
|
|
2041
2593
|
e.stopPropagation();
|
|
2042
2594
|
toggleViewportMenu();
|
|
2043
2595
|
});
|
|
2044
|
-
if (
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2596
|
+
if (widthInp) {
|
|
2597
|
+
widthInp.addEventListener('input', scheduleCustomViewportApply);
|
|
2598
|
+
widthInp.addEventListener('change', applyCustomViewportNow);
|
|
2599
|
+
}
|
|
2600
|
+
if (heightInp) {
|
|
2601
|
+
heightInp.addEventListener('input', scheduleCustomViewportApply);
|
|
2602
|
+
heightInp.addEventListener('change', applyCustomViewportNow);
|
|
2603
|
+
}
|
|
2604
|
+
if (zoomFitBtn) {
|
|
2605
|
+
zoomFitBtn.addEventListener('click', function(e) {
|
|
2606
|
+
e.preventDefault();
|
|
2607
|
+
e.stopPropagation();
|
|
2608
|
+
resetViewportZoomToFit();
|
|
2609
|
+
});
|
|
2610
|
+
}
|
|
2049
2611
|
if (zoomInp) {
|
|
2050
2612
|
zoomInp.addEventListener('change', function() {
|
|
2051
2613
|
var z = clampViewportNumber(zoomInp.value, Math.round(getAppliedViewportZoom() * 100), 25, 200);
|
|
@@ -2080,7 +2642,7 @@ function bindViewportControls() {
|
|
|
2080
2642
|
function switchLeftTab(tab) {
|
|
2081
2643
|
if (tab !== 'elements' && tab !== 'dom-tree') return;
|
|
2082
2644
|
currentLeftTab = tab;
|
|
2083
|
-
var tabs = document.querySelectorAll('.lp-tabs .lp-tab');
|
|
2645
|
+
var tabs = document.querySelectorAll('#left-panel .lp-tabs .lp-tab');
|
|
2084
2646
|
for (var i = 0; i < tabs.length; i++) {
|
|
2085
2647
|
var oc = tabs[i].getAttribute('onclick') || '';
|
|
2086
2648
|
tabs[i].classList.toggle('active', oc.indexOf("switchLeftTab('" + tab + "')") >= 0);
|
|
@@ -2092,18 +2654,26 @@ function switchLeftTab(tab) {
|
|
|
2092
2654
|
}
|
|
2093
2655
|
var inp = document.getElementById('comp-search');
|
|
2094
2656
|
if (tab === 'elements') {
|
|
2095
|
-
inp.placeholder = 'Search elements\u2026';
|
|
2096
2657
|
renderElementsTree(inp.value);
|
|
2097
2658
|
} else if (tab === 'dom-tree') {
|
|
2098
|
-
inp.placeholder = 'Search layers\u2026';
|
|
2099
2659
|
renderDomTree(inp.value);
|
|
2100
2660
|
}
|
|
2101
2661
|
}
|
|
2102
2662
|
|
|
2663
|
+
function expandSectionComponentsBody() {
|
|
2664
|
+
var panel = document.getElementById('section-components-panel');
|
|
2665
|
+
if (!panel) return;
|
|
2666
|
+
var body = panel.querySelector('.lp-body');
|
|
2667
|
+
var toggle = panel.querySelector('.close-section-components-panel');
|
|
2668
|
+
if (body) body.classList.remove('collapsed');
|
|
2669
|
+
if (toggle) toggle.classList.remove('collapsed');
|
|
2670
|
+
}
|
|
2671
|
+
|
|
2103
2672
|
function switchSectionComponentsTab(tab) {
|
|
2104
2673
|
if (tab !== 'components' && tab !== 'sections') return;
|
|
2674
|
+
expandSectionComponentsBody();
|
|
2105
2675
|
currentSectionComponentsTab = tab;
|
|
2106
|
-
var tabs = document.querySelectorAll('
|
|
2676
|
+
var tabs = document.querySelectorAll('#section-components-panel .lp-tabs .lp-tab');
|
|
2107
2677
|
for (var i = 0; i < tabs.length; i++) {
|
|
2108
2678
|
var oc = tabs[i].getAttribute('onclick') || '';
|
|
2109
2679
|
tabs[i].classList.toggle('active', oc.indexOf("switchSectionComponentsTab('" + tab + "')") >= 0);
|
|
@@ -2113,27 +2683,141 @@ function switchSectionComponentsTab(tab) {
|
|
|
2113
2683
|
if (compPane) compPane.classList.toggle('active', tab === 'components');
|
|
2114
2684
|
if (secPane) secPane.classList.toggle('active', tab === 'sections');
|
|
2115
2685
|
var inp = document.getElementById('comp-search');
|
|
2116
|
-
if (inp) inp.placeholder = tab === 'sections' ? 'Search
|
|
2686
|
+
if (inp) inp.placeholder = tab === 'sections' ? 'Search' : 'Search';
|
|
2117
2687
|
renderSidebar(inp ? inp.value : '');
|
|
2118
2688
|
}
|
|
2119
2689
|
|
|
2690
|
+
function toggleSectionComponentsBody() {
|
|
2691
|
+
var panel = document.getElementById('section-components-panel');
|
|
2692
|
+
if (!panel) return;
|
|
2693
|
+
var body = panel.querySelector('.lp-body');
|
|
2694
|
+
var toggle = panel.querySelector('.close-section-components-panel');
|
|
2695
|
+
if (!body) return;
|
|
2696
|
+
var collapsed = body.classList.toggle('collapsed');
|
|
2697
|
+
if (toggle) toggle.classList.toggle('collapsed', collapsed);
|
|
2698
|
+
if (!collapsed) {
|
|
2699
|
+
switchSectionComponentsTab(currentSectionComponentsTab || 'components');
|
|
2700
|
+
}
|
|
2701
|
+
}
|
|
2702
|
+
|
|
2120
2703
|
function toggleSectionComponentsPanel(forceVisible) {
|
|
2121
2704
|
var panel = document.getElementById('section-components-panel');
|
|
2122
2705
|
if (!panel) return;
|
|
2123
|
-
var
|
|
2706
|
+
var body = panel.querySelector('.lp-body');
|
|
2707
|
+
var toggle = panel.querySelector('.close-section-components-panel');
|
|
2708
|
+
if (!body) return;
|
|
2709
|
+
var isCollapsed = body.classList.contains('collapsed');
|
|
2710
|
+
var shouldExpand =
|
|
2124
2711
|
typeof forceVisible === 'boolean'
|
|
2125
2712
|
? forceVisible
|
|
2126
|
-
:
|
|
2127
|
-
|
|
2128
|
-
if (
|
|
2713
|
+
: isCollapsed;
|
|
2714
|
+
body.classList.toggle('collapsed', !shouldExpand);
|
|
2715
|
+
if (toggle) toggle.classList.toggle('collapsed', !shouldExpand);
|
|
2716
|
+
if (shouldExpand) {
|
|
2129
2717
|
switchSectionComponentsTab(currentSectionComponentsTab || 'components');
|
|
2130
2718
|
}
|
|
2131
2719
|
}
|
|
2132
2720
|
|
|
2721
|
+
function handleAddElementClick(e) {
|
|
2722
|
+
if (e) {
|
|
2723
|
+
e.preventDefault();
|
|
2724
|
+
e.stopPropagation();
|
|
2725
|
+
}
|
|
2726
|
+
toggleSectionComponentsPanel();
|
|
2727
|
+
}
|
|
2728
|
+
|
|
2133
2729
|
// \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
|
|
2730
|
+
function closeAllAccSections(exceptName) {
|
|
2731
|
+
var sections = document.querySelectorAll('#rp-accordion .acc-section');
|
|
2732
|
+
for (var i = 0; i < sections.length; i++) {
|
|
2733
|
+
var sec = sections[i];
|
|
2734
|
+
var id = sec.id || '';
|
|
2735
|
+
var name = id.replace(/^acc-/, '');
|
|
2736
|
+
if (exceptName && name === exceptName) continue;
|
|
2737
|
+
sec.classList.remove('open');
|
|
2738
|
+
}
|
|
2739
|
+
}
|
|
2740
|
+
|
|
2741
|
+
function getRpAccordion() {
|
|
2742
|
+
return document.getElementById('rp-accordion');
|
|
2743
|
+
}
|
|
2744
|
+
|
|
2745
|
+
function scrollRpAccordionContainerToTop() {
|
|
2746
|
+
var accordion = getRpAccordion();
|
|
2747
|
+
if (!accordion) return;
|
|
2748
|
+
|
|
2749
|
+
try {
|
|
2750
|
+
accordion.scrollIntoView({ block: 'start', inline: 'nearest' });
|
|
2751
|
+
} catch(_) {
|
|
2752
|
+
try { accordion.scrollIntoView(true); } catch(__) {}
|
|
2753
|
+
}
|
|
2754
|
+
|
|
2755
|
+
var node = accordion.parentElement;
|
|
2756
|
+
while (node) {
|
|
2757
|
+
try {
|
|
2758
|
+
var style = window.getComputedStyle(node);
|
|
2759
|
+
var canScroll = (style.overflowY === 'auto' || style.overflowY === 'scroll') &&
|
|
2760
|
+
node.scrollHeight > node.clientHeight;
|
|
2761
|
+
if (canScroll) {
|
|
2762
|
+
var ar = accordion.getBoundingClientRect();
|
|
2763
|
+
var nr = node.getBoundingClientRect();
|
|
2764
|
+
node.scrollTop = Math.max(0, node.scrollTop + (ar.top - nr.top));
|
|
2765
|
+
break;
|
|
2766
|
+
}
|
|
2767
|
+
} catch(_) {}
|
|
2768
|
+
node = node.parentElement;
|
|
2769
|
+
}
|
|
2770
|
+
}
|
|
2771
|
+
|
|
2772
|
+
function scrollOpenAccSectionIntoView(sec) {
|
|
2773
|
+
var accordion = getRpAccordion();
|
|
2774
|
+
if (!accordion) return;
|
|
2775
|
+
var openSec =
|
|
2776
|
+
(sec && sec.classList.contains('open') && sec.style.display !== 'none')
|
|
2777
|
+
? sec
|
|
2778
|
+
: accordion.querySelector('.acc-section.open');
|
|
2779
|
+
if (!openSec || openSec.style.display === 'none') return;
|
|
2780
|
+
|
|
2781
|
+
function doScroll() {
|
|
2782
|
+
scrollRpAccordionContainerToTop();
|
|
2783
|
+
var ar = accordion.getBoundingClientRect();
|
|
2784
|
+
var sr = openSec.getBoundingClientRect();
|
|
2785
|
+
accordion.scrollTop = Math.max(0, accordion.scrollTop + (sr.top - ar.top));
|
|
2786
|
+
}
|
|
2787
|
+
|
|
2788
|
+
requestAnimationFrame(function() {
|
|
2789
|
+
doScroll();
|
|
2790
|
+
requestAnimationFrame(function() {
|
|
2791
|
+
doScroll();
|
|
2792
|
+
setTimeout(doScroll, 0);
|
|
2793
|
+
});
|
|
2794
|
+
});
|
|
2795
|
+
}
|
|
2796
|
+
|
|
2797
|
+
function openAccSection(name, options) {
|
|
2798
|
+
if (!name) return null;
|
|
2799
|
+
var sec = document.getElementById('acc-' + name);
|
|
2800
|
+
if (!sec || sec.style.display === 'none') return null;
|
|
2801
|
+
closeAllAccSections(name);
|
|
2802
|
+
sec.classList.add('open');
|
|
2803
|
+
if (!options || options.scroll !== false) scrollOpenAccSectionIntoView(sec);
|
|
2804
|
+
return sec;
|
|
2805
|
+
}
|
|
2806
|
+
|
|
2134
2807
|
function toggleAcc(name) {
|
|
2135
2808
|
var sec = document.getElementById('acc-' + name);
|
|
2136
|
-
if (sec
|
|
2809
|
+
if (!sec || sec.style.display === 'none') return;
|
|
2810
|
+
if (sec.classList.contains('open')) {
|
|
2811
|
+
sec.classList.remove('open');
|
|
2812
|
+
return;
|
|
2813
|
+
}
|
|
2814
|
+
openAccSection(name);
|
|
2815
|
+
}
|
|
2816
|
+
|
|
2817
|
+
function focusDesignAccordionSection(name) {
|
|
2818
|
+
if (!name) return;
|
|
2819
|
+
if (currentMainTab !== 'design') switchMainTab('design');
|
|
2820
|
+
openAccSection(name);
|
|
2137
2821
|
}
|
|
2138
2822
|
|
|
2139
2823
|
// \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
|
|
@@ -2200,9 +2884,20 @@ var PROP_META = {
|
|
|
2200
2884
|
'pp-id': {label:'ID', cssProp:null},
|
|
2201
2885
|
'pp-href': {label:'Href', cssProp:null},
|
|
2202
2886
|
'pp-target': {label:'Target', cssProp:null},
|
|
2887
|
+
'pp-rel': {label:'Rel', cssProp:null},
|
|
2888
|
+
'pp-download':{label:'Download', cssProp:null},
|
|
2889
|
+
'pp-link-title': {label:'Title', cssProp:null},
|
|
2890
|
+
'pp-hreflang':{label:'Hreflang', cssProp:null},
|
|
2891
|
+
'pp-link-type': {label:'Link type', cssProp:null},
|
|
2892
|
+
'pp-referrerpolicy': {label:'Referrer policy', cssProp:null},
|
|
2203
2893
|
'pp-src': {label:'Src', cssProp:null},
|
|
2894
|
+
'pp-video-src': {label:'Src', cssProp:null},
|
|
2895
|
+
'pp-video-poster': {label:'Poster', cssProp:null},
|
|
2896
|
+
'pp-youtube-id': {label:'YouTube video ID', cssProp:null},
|
|
2897
|
+
'pp-vimeo-id': {label:'Vimeo video ID', cssProp:null},
|
|
2204
2898
|
'pp-alt': {label:'Alt', cssProp:null},
|
|
2205
2899
|
'pp-ph': {label:'Placeholder', cssProp:null},
|
|
2900
|
+
'pp-value': {label:'Value', cssProp:null},
|
|
2206
2901
|
'pp-text': {label:'Inner text', cssProp:null},
|
|
2207
2902
|
'pp-html': {label:'Inner HTML', cssProp:null},
|
|
2208
2903
|
'pp-mob-css': {label:'Mobile CSS', cssProp:null},
|
|
@@ -2225,9 +2920,20 @@ function getOriginalValue(inputId, el) {
|
|
|
2225
2920
|
case 'pp-id': return el.id || '';
|
|
2226
2921
|
case 'pp-href': return el.getAttribute('href') || '';
|
|
2227
2922
|
case 'pp-target': return el.getAttribute('target') || '';
|
|
2923
|
+
case 'pp-rel': return el.getAttribute('rel') || '';
|
|
2924
|
+
case 'pp-download': return el.getAttribute('download') || '';
|
|
2925
|
+
case 'pp-link-title': return el.getAttribute('title') || '';
|
|
2926
|
+
case 'pp-hreflang': return el.getAttribute('hreflang') || '';
|
|
2927
|
+
case 'pp-link-type': return el.getAttribute('type') || '';
|
|
2928
|
+
case 'pp-referrerpolicy': return el.getAttribute('referrerpolicy') || '';
|
|
2228
2929
|
case 'pp-src': return el.getAttribute('src') || '';
|
|
2930
|
+
case 'pp-video-src': return getVideoSrc(el);
|
|
2931
|
+
case 'pp-video-poster': return el.getAttribute('poster') || '';
|
|
2932
|
+
case 'pp-youtube-id': return getYoutubeVideoId(el);
|
|
2933
|
+
case 'pp-vimeo-id': return getVimeoVideoId(el);
|
|
2229
2934
|
case 'pp-alt': return el.getAttribute('alt') || '';
|
|
2230
2935
|
case 'pp-ph': return el.getAttribute('placeholder') || '';
|
|
2936
|
+
case 'pp-value': return getFormControlValue(el);
|
|
2231
2937
|
case 'pp-css': return el.getAttribute('style') || '';
|
|
2232
2938
|
case 'pp-mob-css': return el.dataset.mobileCss || '';
|
|
2233
2939
|
case 'pp-tab-css': return el.dataset.tabletCss || '';
|
|
@@ -2364,9 +3070,20 @@ function revertChangeOnDom(change) {
|
|
|
2364
3070
|
case 'pp-css': orig ? el.setAttribute('style', orig) : el.removeAttribute('style'); break;
|
|
2365
3071
|
case 'pp-href': orig ? el.setAttribute('href', orig) : el.removeAttribute('href'); break;
|
|
2366
3072
|
case 'pp-target': orig ? el.setAttribute('target', orig) : el.removeAttribute('target'); break;
|
|
3073
|
+
case 'pp-rel': orig ? el.setAttribute('rel', orig) : el.removeAttribute('rel'); break;
|
|
3074
|
+
case 'pp-download': orig ? el.setAttribute('download', orig) : el.removeAttribute('download'); break;
|
|
3075
|
+
case 'pp-link-title': orig ? el.setAttribute('title', orig) : el.removeAttribute('title'); break;
|
|
3076
|
+
case 'pp-hreflang': orig ? el.setAttribute('hreflang', orig) : el.removeAttribute('hreflang'); break;
|
|
3077
|
+
case 'pp-link-type': orig ? el.setAttribute('type', orig) : el.removeAttribute('type'); break;
|
|
3078
|
+
case 'pp-referrerpolicy': orig ? el.setAttribute('referrerpolicy', orig) : el.removeAttribute('referrerpolicy'); break;
|
|
2367
3079
|
case 'pp-src': orig ? el.setAttribute('src', orig) : el.removeAttribute('src'); break;
|
|
3080
|
+
case 'pp-video-src': orig ? setVideoSrc(el, orig) : setVideoSrc(el, ''); break;
|
|
3081
|
+
case 'pp-video-poster': orig ? el.setAttribute('poster', orig) : el.removeAttribute('poster'); break;
|
|
3082
|
+
case 'pp-youtube-id': orig ? setYoutubeVideoId(el, orig) : setYoutubeVideoId(el, ''); break;
|
|
3083
|
+
case 'pp-vimeo-id': orig ? setVimeoVideoId(el, orig) : setVimeoVideoId(el, ''); break;
|
|
2368
3084
|
case 'pp-alt': orig ? el.setAttribute('alt', orig) : el.removeAttribute('alt'); break;
|
|
2369
3085
|
case 'pp-ph': orig ? el.setAttribute('placeholder', orig) : el.removeAttribute('placeholder'); break;
|
|
3086
|
+
case 'pp-value': el.value = orig; break;
|
|
2370
3087
|
case 'pp-mob-css': el.dataset.mobileCss = orig; break;
|
|
2371
3088
|
case 'pp-tab-css': el.dataset.tabletCss = orig; break;
|
|
2372
3089
|
default: console.warn('[V2] revertChangeOnDom: no revert handler for', change.inputId);
|
|
@@ -2390,11 +3107,28 @@ function syncDesignInput(change) {
|
|
|
2390
3107
|
function removeStateChange(idx) {
|
|
2391
3108
|
var change = stateChanges[idx];
|
|
2392
3109
|
if (!change) return;
|
|
3110
|
+
if (
|
|
3111
|
+
change.isStructuralLive &&
|
|
3112
|
+
normalizeChangesetType({ type: change.structuralType }) === 'insert'
|
|
3113
|
+
) {
|
|
3114
|
+
var instId = historyInsertInstanceId(null, change);
|
|
3115
|
+
if (instId) {
|
|
3116
|
+
removeEditorInsertByInstanceId(instId);
|
|
3117
|
+
commitStateChangesForActiveVariation();
|
|
3118
|
+
renderStatesTab();
|
|
3119
|
+
if (currentMainTab === 'history') renderHistoryTab();
|
|
3120
|
+
try {
|
|
3121
|
+
delete varHtmlCache[activeVarId];
|
|
3122
|
+
} catch(_) {}
|
|
3123
|
+
saveCurrentVariationHtml();
|
|
3124
|
+
recomputeEditorDirty();
|
|
3125
|
+
scheduleDomTreeRefresh();
|
|
3126
|
+
return;
|
|
3127
|
+
}
|
|
3128
|
+
}
|
|
2393
3129
|
if (change.isStructuralLive) {
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
change.vveTs,
|
|
2397
|
-
);
|
|
3130
|
+
var varId = change.structuralVarId || activeVarId;
|
|
3131
|
+
removeSessionStructuralRowByTimestamp(varId, change.vveTs);
|
|
2398
3132
|
stateChanges.splice(idx, 1);
|
|
2399
3133
|
commitStateChangesForActiveVariation();
|
|
2400
3134
|
renderStatesTab();
|
|
@@ -2492,10 +3226,28 @@ function captureChangesetSnapshotBeforeApply(entry, el, iframeDoc) {
|
|
|
2492
3226
|
break;
|
|
2493
3227
|
case 'attribute':
|
|
2494
3228
|
if (entry.attribute) {
|
|
3229
|
+
var attrVal = el.getAttribute(entry.attribute);
|
|
3230
|
+
if (
|
|
3231
|
+
String(entry.attribute).toLowerCase() === 'src' &&
|
|
3232
|
+
el.tagName &&
|
|
3233
|
+
el.tagName.toLowerCase() === 'video'
|
|
3234
|
+
) {
|
|
3235
|
+
attrVal = getVideoSrc(el);
|
|
3236
|
+
} else if (
|
|
3237
|
+
String(entry.attribute).toLowerCase() === 'data-youtube-id' &&
|
|
3238
|
+
isYoutubeVideoElement(el)
|
|
3239
|
+
) {
|
|
3240
|
+
attrVal = getYoutubeVideoId(el);
|
|
3241
|
+
} else if (
|
|
3242
|
+
String(entry.attribute).toLowerCase() === 'data-vimeo-id' &&
|
|
3243
|
+
isVimeoVideoElement(el)
|
|
3244
|
+
) {
|
|
3245
|
+
attrVal = getVimeoVideoId(el);
|
|
3246
|
+
}
|
|
2495
3247
|
appliedChangesetSnapshots[k] = {
|
|
2496
3248
|
kind: 'attribute',
|
|
2497
3249
|
name: entry.attribute,
|
|
2498
|
-
v:
|
|
3250
|
+
v: attrVal,
|
|
2499
3251
|
};
|
|
2500
3252
|
}
|
|
2501
3253
|
break;
|
|
@@ -2544,6 +3296,13 @@ function revertChangesetEntryOnDom(entry) {
|
|
|
2544
3296
|
var iframeDoc = document.getElementById('iframeId').contentDocument;
|
|
2545
3297
|
if (!iframeDoc) return false;
|
|
2546
3298
|
var k = entrySnapshotKey(entry);
|
|
3299
|
+
if (normalizeChangesetType(entry) === 'insert') {
|
|
3300
|
+
var instId = instanceIdFromInsertHtml(entry.html);
|
|
3301
|
+
delete appliedChangesetSnapshots[k];
|
|
3302
|
+
if (instId && removeEditorInsertByInstanceId(instId)) return false;
|
|
3303
|
+
softReloadEditorIframe();
|
|
3304
|
+
return true;
|
|
3305
|
+
}
|
|
2547
3306
|
var snap = appliedChangesetSnapshots[k];
|
|
2548
3307
|
var el = querySelectorResolved(iframeDoc, entry.selector);
|
|
2549
3308
|
if (!snap || !el) {
|
|
@@ -2562,7 +3321,23 @@ function revertChangesetEntryOnDom(entry) {
|
|
|
2562
3321
|
if (snap.v) el.setAttribute('style', snap.v);
|
|
2563
3322
|
else el.removeAttribute('style');
|
|
2564
3323
|
} else if (snap.kind === 'attribute' && snap.name) {
|
|
2565
|
-
if (
|
|
3324
|
+
if (
|
|
3325
|
+
String(snap.name).toLowerCase() === 'src' &&
|
|
3326
|
+
el.tagName &&
|
|
3327
|
+
el.tagName.toLowerCase() === 'video'
|
|
3328
|
+
) {
|
|
3329
|
+
setVideoSrc(el, snap.v == null ? '' : snap.v);
|
|
3330
|
+
} else if (
|
|
3331
|
+
String(snap.name).toLowerCase() === 'data-youtube-id' &&
|
|
3332
|
+
isYoutubeVideoElement(el)
|
|
3333
|
+
) {
|
|
3334
|
+
setYoutubeVideoId(el, snap.v == null ? '' : snap.v);
|
|
3335
|
+
} else if (
|
|
3336
|
+
String(snap.name).toLowerCase() === 'data-vimeo-id' &&
|
|
3337
|
+
isVimeoVideoElement(el)
|
|
3338
|
+
) {
|
|
3339
|
+
setVimeoVideoId(el, snap.v == null ? '' : snap.v);
|
|
3340
|
+
} else if (snap.v == null || snap.v === '') el.removeAttribute(snap.name);
|
|
2566
3341
|
else el.setAttribute(snap.name, snap.v);
|
|
2567
3342
|
} else if (snap.kind === 'display') el.style.display = snap.v;
|
|
2568
3343
|
else {
|
|
@@ -2643,6 +3418,42 @@ function formatHistoryRelativeTime(ts) {
|
|
|
2643
3418
|
return day + ' day' + (day === 1 ? '' : 's') + ' ago';
|
|
2644
3419
|
}
|
|
2645
3420
|
|
|
3421
|
+
function findSessionInsertRowForChange(change) {
|
|
3422
|
+
if (!change) return null;
|
|
3423
|
+
var varId = change.structuralVarId || activeVarId;
|
|
3424
|
+
var arr = varId && sessionStructuralChainRowsByVarId[varId];
|
|
3425
|
+
if (!arr || !arr.length) return null;
|
|
3426
|
+
var instId = '';
|
|
3427
|
+
try {
|
|
3428
|
+
if (change.targetEl && change.targetEl.getAttribute) {
|
|
3429
|
+
instId = change.targetEl.getAttribute('data-vve-instance') || '';
|
|
3430
|
+
}
|
|
3431
|
+
} catch(_) {}
|
|
3432
|
+
for (var i = 0; i < arr.length; i++) {
|
|
3433
|
+
var row = arr[i];
|
|
3434
|
+
if (!row || normalizeChangesetType(row) !== 'insert') continue;
|
|
3435
|
+
if (change.vveTs && row.vveTs === change.vveTs) return row;
|
|
3436
|
+
if (instId && instanceIdFromInsertHtml(row.html) === instId) return row;
|
|
3437
|
+
}
|
|
3438
|
+
return null;
|
|
3439
|
+
}
|
|
3440
|
+
|
|
3441
|
+
function historyInsertInstanceId(entry, change) {
|
|
3442
|
+
if (entry && normalizeChangesetType(entry) === 'insert') {
|
|
3443
|
+
return instanceIdFromInsertHtml(entry.html);
|
|
3444
|
+
}
|
|
3445
|
+
if (change && change.isStructuralLive && normalizeChangesetType({ type: change.structuralType }) === 'insert') {
|
|
3446
|
+
var row = findSessionInsertRowForChange(change);
|
|
3447
|
+
if (row) return instanceIdFromInsertHtml(row.html);
|
|
3448
|
+
try {
|
|
3449
|
+
if (change.targetEl && change.targetEl.getAttribute) {
|
|
3450
|
+
return change.targetEl.getAttribute('data-vve-instance') || '';
|
|
3451
|
+
}
|
|
3452
|
+
} catch(_) {}
|
|
3453
|
+
}
|
|
3454
|
+
return '';
|
|
3455
|
+
}
|
|
3456
|
+
|
|
2646
3457
|
function getUnifiedHistoryItems() {
|
|
2647
3458
|
var out = [];
|
|
2648
3459
|
var v = getActiveVariationForHistory();
|
|
@@ -2652,6 +3463,7 @@ function getUnifiedHistoryItems() {
|
|
|
2652
3463
|
out.push({
|
|
2653
3464
|
source: 'saved',
|
|
2654
3465
|
idx: i,
|
|
3466
|
+
insertInstanceId: historyInsertInstanceId(e, null),
|
|
2655
3467
|
selector: (e && e.selector) || '(unknown)',
|
|
2656
3468
|
label: historyEntryTypeLabel(e),
|
|
2657
3469
|
value: historyEntryValuePreview(e),
|
|
@@ -2668,6 +3480,7 @@ function getUnifiedHistoryItems() {
|
|
|
2668
3480
|
out.push({
|
|
2669
3481
|
source: 'live',
|
|
2670
3482
|
idx: j,
|
|
3483
|
+
insertInstanceId: historyInsertInstanceId(null, c),
|
|
2671
3484
|
selector: c.selector || '(unknown)',
|
|
2672
3485
|
label: c.label || 'Live change',
|
|
2673
3486
|
value: c.value != null ? String(c.value).slice(0, 120) : '',
|
|
@@ -2701,11 +3514,15 @@ function renderHistoryTab() {
|
|
|
2701
3514
|
var title = 'Edit - ' + (it.label || 'Change');
|
|
2702
3515
|
var avatarLabel = it.source === 'live' ? 'Y' : 'S';
|
|
2703
3516
|
var timeText = formatHistoryRelativeTime(it.ts) || (it.tsLabel || '');
|
|
3517
|
+
var removeOnclick = it.insertInstanceId
|
|
3518
|
+
? 'removeHistoryItem("' + esc(it.source) + '",' + it.idx + ', event, "' + esc(it.insertInstanceId) + '")'
|
|
3519
|
+
: 'removeHistoryItem("' + esc(it.source) + '",' + it.idx + ', event)';
|
|
2704
3520
|
html +=
|
|
2705
3521
|
'<div class="history-item" role="button" tabindex="0" title="Jump to element in iframe" onclick="focusHistoryItem("' +
|
|
2706
3522
|
esc(it.source) +
|
|
2707
3523
|
'",' +
|
|
2708
3524
|
it.idx +
|
|
3525
|
+
(it.insertInstanceId ? ', "' + esc(it.insertInstanceId) + '"' : '') +
|
|
2709
3526
|
')">' +
|
|
2710
3527
|
'<span class="history-dot"></span>' +
|
|
2711
3528
|
'<div class="history-card">' +
|
|
@@ -2716,18 +3533,16 @@ function renderHistoryTab() {
|
|
|
2716
3533
|
'</div>' +
|
|
2717
3534
|
'<div class="history-time">' + esc(timeText || 'n/a') + '</div>' +
|
|
2718
3535
|
'</div>' +
|
|
2719
|
-
'<button type="button" class="state-remove history-remove" title="Remove this change" onclick="
|
|
2720
|
-
|
|
2721
|
-
'
|
|
2722
|
-
it.idx +
|
|
2723
|
-
', event)">✕</button>' +
|
|
3536
|
+
'<button type="button" class="state-remove history-remove" title="Remove this change" onclick="' +
|
|
3537
|
+
removeOnclick +
|
|
3538
|
+
'">✕</button>' +
|
|
2724
3539
|
'</div>';
|
|
2725
3540
|
}
|
|
2726
3541
|
html += '</div>';
|
|
2727
3542
|
container.innerHTML = html;
|
|
2728
3543
|
}
|
|
2729
3544
|
|
|
2730
|
-
function focusHistoryItem(source, idx) {
|
|
3545
|
+
function focusHistoryItem(source, idx, insertInstanceId) {
|
|
2731
3546
|
if (source === 'live') {
|
|
2732
3547
|
var change = stateChanges[idx];
|
|
2733
3548
|
if (!change || !change.selector) return;
|
|
@@ -2735,6 +3550,20 @@ function focusHistoryItem(source, idx) {
|
|
|
2735
3550
|
var iframe = document.getElementById('iframeId');
|
|
2736
3551
|
var iframeDoc = iframe && iframe.contentDocument;
|
|
2737
3552
|
if (!iframeDoc) return;
|
|
3553
|
+
var instId = insertInstanceId || historyInsertInstanceId(null, change);
|
|
3554
|
+
if (instId) {
|
|
3555
|
+
var safeInst = String(instId).split('"').join('\\"');
|
|
3556
|
+
var insertedEl = iframeDoc.querySelector('[data-vve-instance="' + safeInst + '"]');
|
|
3557
|
+
if (insertedEl) {
|
|
3558
|
+
selectElement(insertedEl);
|
|
3559
|
+
try {
|
|
3560
|
+
insertedEl.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'nearest' });
|
|
3561
|
+
} catch(_) {
|
|
3562
|
+
insertedEl.scrollIntoView();
|
|
3563
|
+
}
|
|
3564
|
+
return;
|
|
3565
|
+
}
|
|
3566
|
+
}
|
|
2738
3567
|
var el = querySelectorResolved(iframeDoc, change.selector);
|
|
2739
3568
|
if (!el) return;
|
|
2740
3569
|
selectElement(el);
|
|
@@ -2746,12 +3575,25 @@ function focusHistoryItem(source, idx) {
|
|
|
2746
3575
|
} catch(_) {}
|
|
2747
3576
|
return;
|
|
2748
3577
|
}
|
|
2749
|
-
focusHistoryChangeset(idx);
|
|
3578
|
+
focusHistoryChangeset(idx, insertInstanceId);
|
|
2750
3579
|
}
|
|
2751
3580
|
|
|
2752
|
-
function removeHistoryItem(source, idx, evt) {
|
|
3581
|
+
function removeHistoryItem(source, idx, evt, insertInstanceId) {
|
|
3582
|
+
if (evt && evt.stopPropagation) evt.stopPropagation();
|
|
3583
|
+
if (insertInstanceId) {
|
|
3584
|
+
removeEditorInsertByInstanceId(insertInstanceId);
|
|
3585
|
+
commitStateChangesForActiveVariation();
|
|
3586
|
+
try {
|
|
3587
|
+
delete varHtmlCache[activeVarId];
|
|
3588
|
+
} catch(_) {}
|
|
3589
|
+
saveCurrentVariationHtml();
|
|
3590
|
+
recomputeEditorDirty();
|
|
3591
|
+
if (currentMainTab === 'states') renderStatesTab();
|
|
3592
|
+
if (currentMainTab === 'history') renderHistoryTab();
|
|
3593
|
+
scheduleDomTreeRefresh();
|
|
3594
|
+
return;
|
|
3595
|
+
}
|
|
2753
3596
|
if (source === 'live') {
|
|
2754
|
-
if (evt && evt.stopPropagation) evt.stopPropagation();
|
|
2755
3597
|
removeStateChange(idx);
|
|
2756
3598
|
if (currentMainTab === 'history') renderHistoryTab();
|
|
2757
3599
|
return;
|
|
@@ -2790,7 +3632,7 @@ function isStyleOnlyChangesetEntry(entry) {
|
|
|
2790
3632
|
return false;
|
|
2791
3633
|
}
|
|
2792
3634
|
|
|
2793
|
-
function focusHistoryChangeset(idx) {
|
|
3635
|
+
function focusHistoryChangeset(idx, insertInstanceId) {
|
|
2794
3636
|
var v = getActiveVariationForHistory();
|
|
2795
3637
|
if (!v) return;
|
|
2796
3638
|
var arr = parseVariationChangesets(v);
|
|
@@ -2801,6 +3643,20 @@ function focusHistoryChangeset(idx) {
|
|
|
2801
3643
|
var iframe = document.getElementById('iframeId');
|
|
2802
3644
|
var iframeDoc = iframe && iframe.contentDocument;
|
|
2803
3645
|
if (!iframeDoc) return;
|
|
3646
|
+
var instId = insertInstanceId || historyInsertInstanceId(entry, null);
|
|
3647
|
+
if (instId) {
|
|
3648
|
+
var safeInst = String(instId).split('"').join('\\"');
|
|
3649
|
+
var insertedEl = iframeDoc.querySelector('[data-vve-instance="' + safeInst + '"]');
|
|
3650
|
+
if (insertedEl) {
|
|
3651
|
+
selectElement(insertedEl);
|
|
3652
|
+
try {
|
|
3653
|
+
insertedEl.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'nearest' });
|
|
3654
|
+
} catch(_) {
|
|
3655
|
+
insertedEl.scrollIntoView();
|
|
3656
|
+
}
|
|
3657
|
+
return;
|
|
3658
|
+
}
|
|
3659
|
+
}
|
|
2804
3660
|
var el = querySelectorResolved(iframeDoc, entry.selector);
|
|
2805
3661
|
if (!el) return;
|
|
2806
3662
|
selectElement(el);
|
|
@@ -2842,6 +3698,10 @@ function removeHistoryChangeset(idx, evt) {
|
|
|
2842
3698
|
var removedIsStructural = removedType === 'insert' || removedType === 'reorder';
|
|
2843
3699
|
if (didReload) {
|
|
2844
3700
|
/* revertChangesetEntryOnDom already kicked off iframe reload */
|
|
3701
|
+
} else if (removedType === 'insert') {
|
|
3702
|
+
try {
|
|
3703
|
+
saveCurrentVariationHtml();
|
|
3704
|
+
} catch(_) {}
|
|
2845
3705
|
} else if (removedIsStructural) {
|
|
2846
3706
|
softReloadEditorIframe();
|
|
2847
3707
|
} else if (hasStructuralRemaining) {
|
|
@@ -3510,6 +4370,14 @@ function loadPage(proxyUrl) {
|
|
|
3510
4370
|
// \u2500\u2500 Variation management \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
3511
4371
|
var VAR_COLORS = ['#0069A8','#CA3500','#00786F','#ec4899','#14b8a6','#f59e0b','#8b5cf6','#ef4444'];
|
|
3512
4372
|
|
|
4373
|
+
function varColorAlpha(hex, alpha) {
|
|
4374
|
+
var h = hex.slice(1);
|
|
4375
|
+
return 'rgba(' +
|
|
4376
|
+
parseInt(h.slice(0, 2), 16) + ',' +
|
|
4377
|
+
parseInt(h.slice(2, 4), 16) + ',' +
|
|
4378
|
+
parseInt(h.slice(4, 6), 16) + ',' + alpha + ')';
|
|
4379
|
+
}
|
|
4380
|
+
|
|
3513
4381
|
function renderVariationTabs() {
|
|
3514
4382
|
var container = document.getElementById('variation-tabs');
|
|
3515
4383
|
container.innerHTML = '';
|
|
@@ -3521,7 +4389,12 @@ function renderVariationTabs() {
|
|
|
3521
4389
|
btn.onclick = function() { switchVariation(v._id); };
|
|
3522
4390
|
var dot = document.createElement('span');
|
|
3523
4391
|
dot.className = 'var-dot';
|
|
3524
|
-
|
|
4392
|
+
var color = VAR_COLORS[i % VAR_COLORS.length];
|
|
4393
|
+
btn.setAttribute('data-color', color);
|
|
4394
|
+
btn.style.setProperty('--var-tab-color', color);
|
|
4395
|
+
dot.setAttribute('data-color', color);
|
|
4396
|
+
dot.style.background = color;
|
|
4397
|
+
dot.style.boxShadow = '0 0 0 3px ' + varColorAlpha(color, 0.5);
|
|
3525
4398
|
btn.appendChild(dot);
|
|
3526
4399
|
btn.appendChild(document.createTextNode(label));
|
|
3527
4400
|
container.appendChild(btn);
|
|
@@ -3722,6 +4595,29 @@ function removeSessionStructuralRowByTimestamp(varId, ts) {
|
|
|
3722
4595
|
}
|
|
3723
4596
|
}
|
|
3724
4597
|
|
|
4598
|
+
function removeStructuralStateChangeByTimestamp(varId, ts) {
|
|
4599
|
+
if (!varId || !ts) return;
|
|
4600
|
+
for (var i = stateChanges.length - 1; i >= 0; i--) {
|
|
4601
|
+
var c = stateChanges[i];
|
|
4602
|
+
if (
|
|
4603
|
+
c &&
|
|
4604
|
+
c.isStructuralLive &&
|
|
4605
|
+
c.vveTs === ts &&
|
|
4606
|
+
(c.structuralVarId || activeVarId) === varId
|
|
4607
|
+
) {
|
|
4608
|
+
stateChanges.splice(i, 1);
|
|
4609
|
+
}
|
|
4610
|
+
}
|
|
4611
|
+
}
|
|
4612
|
+
|
|
4613
|
+
/** Undo a session insert when its root node is deleted \u2014 avoids orphan remove rows that match re-inserts at the same slot. */
|
|
4614
|
+
function cancelSessionInsertForElement(varId, el) {
|
|
4615
|
+
if (!varId || !el) return false;
|
|
4616
|
+
var inst = el.getAttribute && el.getAttribute('data-vve-instance');
|
|
4617
|
+
if (!inst || !String(inst).trim()) return false;
|
|
4618
|
+
return removeEditorInsertByInstanceId(inst, { skipDom: true, varId: varId });
|
|
4619
|
+
}
|
|
4620
|
+
|
|
3725
4621
|
/** One States-tab row -> Conversion.io chain-set shape (matches applyChangesetEntry). */
|
|
3726
4622
|
function stateChangeToChainSet(c) {
|
|
3727
4623
|
if (!c || !c.selector) return null;
|
|
@@ -3747,12 +4643,34 @@ function stateChangeToChainSet(c) {
|
|
|
3747
4643
|
return { selector: c.selector, type: 'attribute', attribute: 'href', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
3748
4644
|
case 'pp-target':
|
|
3749
4645
|
return { selector: c.selector, type: 'attribute', attribute: 'target', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4646
|
+
case 'pp-rel':
|
|
4647
|
+
return { selector: c.selector, type: 'attribute', attribute: 'rel', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4648
|
+
case 'pp-download':
|
|
4649
|
+
return { selector: c.selector, type: 'attribute', attribute: 'download', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4650
|
+
case 'pp-link-title':
|
|
4651
|
+
return { selector: c.selector, type: 'attribute', attribute: 'title', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4652
|
+
case 'pp-hreflang':
|
|
4653
|
+
return { selector: c.selector, type: 'attribute', attribute: 'hreflang', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4654
|
+
case 'pp-link-type':
|
|
4655
|
+
return { selector: c.selector, type: 'attribute', attribute: 'type', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4656
|
+
case 'pp-referrerpolicy':
|
|
4657
|
+
return { selector: c.selector, type: 'attribute', attribute: 'referrerpolicy', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
3750
4658
|
case 'pp-src':
|
|
3751
4659
|
return { selector: c.selector, type: 'attribute', attribute: 'src', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4660
|
+
case 'pp-video-src':
|
|
4661
|
+
return { selector: c.selector, type: 'attribute', attribute: 'src', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4662
|
+
case 'pp-video-poster':
|
|
4663
|
+
return { selector: c.selector, type: 'attribute', attribute: 'poster', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4664
|
+
case 'pp-youtube-id':
|
|
4665
|
+
return { selector: c.selector, type: 'attribute', attribute: 'data-youtube-id', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4666
|
+
case 'pp-vimeo-id':
|
|
4667
|
+
return { selector: c.selector, type: 'attribute', attribute: 'data-vimeo-id', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
3752
4668
|
case 'pp-alt':
|
|
3753
4669
|
return { selector: c.selector, type: 'attribute', attribute: 'alt', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
3754
4670
|
case 'pp-ph':
|
|
3755
4671
|
return { selector: c.selector, type: 'attribute', attribute: 'placeholder', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
4672
|
+
case 'pp-value':
|
|
4673
|
+
return { selector: c.selector, type: 'attribute', attribute: 'value', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
3756
4674
|
case 'pp-css':
|
|
3757
4675
|
return { selector: c.selector, type: 'attribute', attribute: 'style', value: c.value, vveTs: c.vveTs || nextHistoryTimestamp() };
|
|
3758
4676
|
case 'pp-mob-css':
|
|
@@ -4012,7 +4930,25 @@ function applyChangesetEntry(entry, iframeDoc) {
|
|
|
4012
4930
|
case 'attribute':
|
|
4013
4931
|
if (entry.attribute && entry.value != null) {
|
|
4014
4932
|
if (String(entry.attribute).toLowerCase() === 'style') break;
|
|
4015
|
-
|
|
4933
|
+
if (
|
|
4934
|
+
String(entry.attribute).toLowerCase() === 'src' &&
|
|
4935
|
+
el.tagName &&
|
|
4936
|
+
el.tagName.toLowerCase() === 'video'
|
|
4937
|
+
) {
|
|
4938
|
+
setVideoSrc(el, entry.value);
|
|
4939
|
+
} else if (
|
|
4940
|
+
String(entry.attribute).toLowerCase() === 'data-youtube-id' &&
|
|
4941
|
+
isYoutubeVideoElement(el)
|
|
4942
|
+
) {
|
|
4943
|
+
setYoutubeVideoId(el, entry.value);
|
|
4944
|
+
} else if (
|
|
4945
|
+
String(entry.attribute).toLowerCase() === 'data-vimeo-id' &&
|
|
4946
|
+
isVimeoVideoElement(el)
|
|
4947
|
+
) {
|
|
4948
|
+
setVimeoVideoId(el, entry.value);
|
|
4949
|
+
} else {
|
|
4950
|
+
el.setAttribute(entry.attribute, entry.value);
|
|
4951
|
+
}
|
|
4016
4952
|
}
|
|
4017
4953
|
break;
|
|
4018
4954
|
case 'insert': {
|
|
@@ -4021,9 +4957,12 @@ function applyChangesetEntry(entry, iframeDoc) {
|
|
|
4021
4957
|
if (structuralDedupeKey) appliedStructuralChangesetKeys[structuralDedupeKey] = true;
|
|
4022
4958
|
break;
|
|
4023
4959
|
}
|
|
4024
|
-
case 'remove':
|
|
4960
|
+
case 'remove': {
|
|
4961
|
+
var inst = el.getAttribute && el.getAttribute('data-vve-instance');
|
|
4962
|
+
if (inst && String(entry.selector || '').indexOf('data-vve-instance') < 0) break;
|
|
4025
4963
|
el.style.display = 'none';
|
|
4026
4964
|
break;
|
|
4965
|
+
}
|
|
4027
4966
|
case 'reorder': {
|
|
4028
4967
|
var target = entry.targetSelector ? querySelectorResolved(iframeDoc, entry.targetSelector) : null;
|
|
4029
4968
|
if (!target || !el.parentNode || !target.parentNode) break;
|
|
@@ -4200,7 +5139,7 @@ function startIframeContentApplyWatcher(navGen, prevDocRef) {
|
|
|
4200
5139
|
}
|
|
4201
5140
|
|
|
4202
5141
|
// \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
|
|
4203
|
-
function selectElement(el) {
|
|
5142
|
+
function selectElement(el, options) {
|
|
4204
5143
|
beginSuppressIframeMutationDirty();
|
|
4205
5144
|
try {
|
|
4206
5145
|
if (selectedEl) { try { selectedEl.classList.remove('vve-selected'); } catch(_) {} }
|
|
@@ -4214,7 +5153,7 @@ function selectElement(el) {
|
|
|
4214
5153
|
document.getElementById('bc-path').textContent = buildSelector(el);
|
|
4215
5154
|
document.getElementById('bc-path').style.color = 'var(--accent-txt)';
|
|
4216
5155
|
document.getElementById('no-sel').style.display = 'none';
|
|
4217
|
-
renderRightPanel(el);
|
|
5156
|
+
renderRightPanel(el, options);
|
|
4218
5157
|
updateSelectionToolbar();
|
|
4219
5158
|
if (currentLeftTab === 'elements' || currentLeftTab === 'dom-tree') {
|
|
4220
5159
|
var treeRootId = currentLeftTab === 'elements' ? 'elements-root' : 'dom-tree-root';
|
|
@@ -4243,7 +5182,11 @@ function deselectElement(options) {
|
|
|
4243
5182
|
document.getElementById('rp-accordion').style.display = 'none';
|
|
4244
5183
|
document.getElementById('bc-path').textContent = 'No element selected';
|
|
4245
5184
|
document.getElementById('bc-path').style.color = 'var(--text-3)';
|
|
4246
|
-
|
|
5185
|
+
var preserveMainTab =
|
|
5186
|
+
!!(options && options.preserveMainTab) ||
|
|
5187
|
+
currentMainTab === 'history' ||
|
|
5188
|
+
currentMainTab === 'states';
|
|
5189
|
+
if (!preserveMainTab) switchMainTab('design');
|
|
4247
5190
|
if (!skipToolbarUpdate) updateSelectionToolbar();
|
|
4248
5191
|
syncDomTreeSelection();
|
|
4249
5192
|
} finally {
|
|
@@ -4330,6 +5273,30 @@ function setDragHandleActive(on) {
|
|
|
4330
5273
|
}
|
|
4331
5274
|
}
|
|
4332
5275
|
|
|
5276
|
+
function getIframeElementVisualRect(el) {
|
|
5277
|
+
var iframe = document.getElementById('iframeId');
|
|
5278
|
+
if (!el || !iframe) return null;
|
|
5279
|
+
// Element rects from the iframe document are in iframe viewport space, not the shell viewport.
|
|
5280
|
+
var elR = el.getBoundingClientRect();
|
|
5281
|
+
var iframeR = iframe.getBoundingClientRect();
|
|
5282
|
+
var cw = iframe.clientWidth || iframe.offsetWidth || 1;
|
|
5283
|
+
var ch = iframe.clientHeight || iframe.offsetHeight || 1;
|
|
5284
|
+
var scaleX = iframeR.width / cw;
|
|
5285
|
+
var scaleY = iframeR.height / ch;
|
|
5286
|
+
var top = iframeR.top + elR.top * scaleY;
|
|
5287
|
+
var left = iframeR.left + elR.left * scaleX;
|
|
5288
|
+
var width = elR.width * scaleX;
|
|
5289
|
+
var height = elR.height * scaleY;
|
|
5290
|
+
return {
|
|
5291
|
+
left: left,
|
|
5292
|
+
top: top,
|
|
5293
|
+
width: width,
|
|
5294
|
+
height: height,
|
|
5295
|
+
right: left + width,
|
|
5296
|
+
bottom: top + height,
|
|
5297
|
+
};
|
|
5298
|
+
}
|
|
5299
|
+
|
|
4333
5300
|
function positionSelectionToolbar() {
|
|
4334
5301
|
var bar = document.getElementById('selection-floater');
|
|
4335
5302
|
var iframe = document.getElementById('iframeId');
|
|
@@ -4341,16 +5308,20 @@ function positionSelectionToolbar() {
|
|
|
4341
5308
|
renderRightPanel(liveSelected);
|
|
4342
5309
|
syncDomTreeSelection();
|
|
4343
5310
|
}
|
|
4344
|
-
var elR = selectedEl
|
|
4345
|
-
|
|
5311
|
+
var elR = getIframeElementVisualRect(selectedEl);
|
|
5312
|
+
if (!elR) return;
|
|
4346
5313
|
var panelR = panel.getBoundingClientRect();
|
|
4347
|
-
var
|
|
4348
|
-
var
|
|
4349
|
-
|
|
4350
|
-
var
|
|
4351
|
-
|
|
5314
|
+
var panelScrollLeft = panel.scrollLeft || 0;
|
|
5315
|
+
var panelScrollTop = panel.scrollTop || 0;
|
|
5316
|
+
var left = elR.left - panelR.left + panelScrollLeft + elR.width / 2 - bar.offsetWidth / 2;
|
|
5317
|
+
var top = elR.top - panelR.top + panelScrollTop - bar.offsetHeight - 8;
|
|
5318
|
+
if (top < panelScrollTop + 6) top = elR.bottom - panelR.top + panelScrollTop + 8;
|
|
5319
|
+
var minL = panelScrollLeft + 6;
|
|
5320
|
+
var maxL = panelScrollLeft + Math.max(6, panel.clientWidth - bar.offsetWidth - 8);
|
|
5321
|
+
left = Math.max(minL, Math.min(left, maxL));
|
|
4352
5322
|
bar.style.left = Math.round(left) + 'px';
|
|
4353
5323
|
bar.style.top = Math.round(top) + 'px';
|
|
5324
|
+
syncMoveFloaterButtons(selectedEl);
|
|
4354
5325
|
}
|
|
4355
5326
|
|
|
4356
5327
|
function updateSelectionToolbar() {
|
|
@@ -4368,6 +5339,7 @@ function updateSelectionToolbar() {
|
|
|
4368
5339
|
if (selectedEl !== liveSelected) selectedEl = liveSelected;
|
|
4369
5340
|
selectedElFingerprint = buildSelector(liveSelected);
|
|
4370
5341
|
bar.style.display = 'flex';
|
|
5342
|
+
syncMoveFloaterButtons(liveSelected);
|
|
4371
5343
|
requestAnimationFrame(function() { positionSelectionToolbar(); });
|
|
4372
5344
|
}
|
|
4373
5345
|
|
|
@@ -4384,6 +5356,11 @@ function bindSelectionToolbarScroll() {
|
|
|
4384
5356
|
}
|
|
4385
5357
|
selectionScrollWin = w;
|
|
4386
5358
|
w.addEventListener('scroll', onFloaterScroll, true);
|
|
5359
|
+
var panel = document.getElementById('iframe-panel');
|
|
5360
|
+
if (panel && !selectionPanelScrollBound) {
|
|
5361
|
+
selectionPanelScrollBound = true;
|
|
5362
|
+
panel.addEventListener('scroll', onFloaterScroll, { passive: true });
|
|
5363
|
+
}
|
|
4387
5364
|
if (!selectionResizeBound) {
|
|
4388
5365
|
selectionResizeBound = true;
|
|
4389
5366
|
window.addEventListener('resize', onFloaterScroll);
|
|
@@ -4405,7 +5382,6 @@ function scrollIframeElementIntoView(el) {
|
|
|
4405
5382
|
function selectElementFromTree(el) {
|
|
4406
5383
|
selectElement(el);
|
|
4407
5384
|
scrollIframeElementIntoView(el);
|
|
4408
|
-
if (currentMainTab !== 'design') switchMainTab('design');
|
|
4409
5385
|
}
|
|
4410
5386
|
|
|
4411
5387
|
function duplicateSelectedEl() {
|
|
@@ -4478,12 +5454,26 @@ function toggleHideSelectedEl() {
|
|
|
4478
5454
|
|
|
4479
5455
|
function deleteSelectedEl() {
|
|
4480
5456
|
if (!selectedEl || !selectedEl.parentNode) return;
|
|
5457
|
+
var inst = selectedEl.getAttribute && selectedEl.getAttribute('data-vve-instance');
|
|
5458
|
+
if (inst && activeVarId && removeEditorInsertByInstanceId(inst)) {
|
|
5459
|
+
saveCurrentVariationHtml();
|
|
5460
|
+
recomputeEditorDirty();
|
|
5461
|
+
deselectElement();
|
|
5462
|
+
scheduleDomTreeRefresh();
|
|
5463
|
+
if (currentMainTab === 'history') renderHistoryTab();
|
|
5464
|
+
return;
|
|
5465
|
+
}
|
|
4481
5466
|
var delSel = buildSelector(selectedEl);
|
|
5467
|
+
var cancelledInsert =
|
|
5468
|
+
activeVarId && cancelSessionInsertForElement(activeVarId, selectedEl);
|
|
4482
5469
|
selectedEl.remove();
|
|
4483
|
-
if (activeVarId) {
|
|
5470
|
+
if (activeVarId && !cancelledInsert) {
|
|
4484
5471
|
var delRow = { selector: delSel, type: 'remove' };
|
|
4485
5472
|
appendSessionStructuralChainRow(activeVarId, delRow);
|
|
4486
5473
|
logStructuralStateChange(delRow, 'Deleted via toolbar', 'Element removed', null);
|
|
5474
|
+
} else if (cancelledInsert) {
|
|
5475
|
+
commitStateChangesForActiveVariation();
|
|
5476
|
+
if (currentMainTab === 'history') renderHistoryTab();
|
|
4487
5477
|
}
|
|
4488
5478
|
saveCurrentVariationHtml();
|
|
4489
5479
|
recomputeEditorDirty();
|
|
@@ -4509,35 +5499,190 @@ function syncDomTreeSelection() {
|
|
|
4509
5499
|
}
|
|
4510
5500
|
}
|
|
4511
5501
|
|
|
4512
|
-
function scheduleDomTreeRefresh() {
|
|
4513
|
-
if (
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
var
|
|
4518
|
-
|
|
4519
|
-
if (currentLeftTab === '
|
|
4520
|
-
|
|
4521
|
-
|
|
5502
|
+
function scheduleDomTreeRefresh() {
|
|
5503
|
+
if (domTreeRefreshTimer) clearTimeout(domTreeRefreshTimer);
|
|
5504
|
+
domTreeRefreshTimer = setTimeout(function() {
|
|
5505
|
+
domTreeRefreshTimer = null;
|
|
5506
|
+
var inp = document.getElementById('comp-search');
|
|
5507
|
+
var q = inp ? inp.value : '';
|
|
5508
|
+
renderElementsTree(q);
|
|
5509
|
+
if (currentLeftTab === 'dom-tree') renderDomTree(q);
|
|
5510
|
+
}, 150);
|
|
5511
|
+
}
|
|
5512
|
+
|
|
5513
|
+
function setDomTreeStatus(mode) {
|
|
5514
|
+
var root = document.getElementById('dom-tree-root');
|
|
5515
|
+
if (!root) return;
|
|
5516
|
+
if (mode === 'empty') {
|
|
5517
|
+
root.innerHTML = '<div class="dt-muted">Load a page to see the DOM tree.</div>';
|
|
5518
|
+
}
|
|
5519
|
+
}
|
|
5520
|
+
|
|
5521
|
+
function domTreePathSegment(el) {
|
|
5522
|
+
var tag = el.tagName.toLowerCase();
|
|
5523
|
+
var idx = 1;
|
|
5524
|
+
var s = el.previousElementSibling;
|
|
5525
|
+
while (s) {
|
|
5526
|
+
if (s.tagName === el.tagName) idx++;
|
|
5527
|
+
s = s.previousElementSibling;
|
|
5528
|
+
}
|
|
5529
|
+
return tag + '[' + idx + ']';
|
|
5530
|
+
}
|
|
5531
|
+
|
|
5532
|
+
function instanceIdFromInsertHtml(html) {
|
|
5533
|
+
var m = String(html || '').match(/data-vve-instance=["']([^"']+)["']/);
|
|
5534
|
+
return m ? m[1] : '';
|
|
5535
|
+
}
|
|
5536
|
+
|
|
5537
|
+
function resolveInsertedElementFromEntry(doc, entry) {
|
|
5538
|
+
if (!doc || !entry) return null;
|
|
5539
|
+
var instId = instanceIdFromInsertHtml(entry.html);
|
|
5540
|
+
if (!instId) return null;
|
|
5541
|
+
try {
|
|
5542
|
+
var safe = String(instId).split('"').join('\\"');
|
|
5543
|
+
return doc.querySelector('[data-vve-instance="' + safe + '"]');
|
|
5544
|
+
} catch(_) {
|
|
5545
|
+
return null;
|
|
5546
|
+
}
|
|
5547
|
+
}
|
|
5548
|
+
|
|
5549
|
+
function removeInsertFromDomByEntry(entry, iframeDoc) {
|
|
5550
|
+
if (!entry || !iframeDoc) return false;
|
|
5551
|
+
var insertedEl = resolveInsertedElementFromEntry(iframeDoc, entry);
|
|
5552
|
+
if (!insertedEl || !insertedEl.parentNode) return false;
|
|
5553
|
+
if (
|
|
5554
|
+
selectedEl &&
|
|
5555
|
+
(selectedEl === insertedEl || (insertedEl.contains && insertedEl.contains(selectedEl)))
|
|
5556
|
+
) {
|
|
5557
|
+
deselectElement();
|
|
5558
|
+
}
|
|
5559
|
+
insertedEl.remove();
|
|
5560
|
+
return true;
|
|
5561
|
+
}
|
|
5562
|
+
|
|
5563
|
+
/** Remove an editor insert everywhere (DOM + session + saved changesets + live history), keyed by data-vve-instance. */
|
|
5564
|
+
function removeEditorInsertByInstanceId(instId, opts) {
|
|
5565
|
+
if (!instId || !String(instId).trim()) return false;
|
|
5566
|
+
opts = opts || {};
|
|
5567
|
+
var varId = opts.varId || activeVarId;
|
|
5568
|
+
if (!varId) return false;
|
|
5569
|
+
var needle = 'data-vve-instance="' + String(instId).split('"').join('\\"') + '"';
|
|
5570
|
+
var didWork = false;
|
|
5571
|
+
|
|
5572
|
+
if (!opts.skipDom) {
|
|
5573
|
+
var iframeDoc = document.getElementById('iframeId').contentDocument;
|
|
5574
|
+
if (iframeDoc) {
|
|
5575
|
+
try {
|
|
5576
|
+
var safe = String(instId).split('"').join('\\"');
|
|
5577
|
+
var el = iframeDoc.querySelector('[data-vve-instance="' + safe + '"]');
|
|
5578
|
+
if (el && el.parentNode) {
|
|
5579
|
+
if (
|
|
5580
|
+
selectedEl &&
|
|
5581
|
+
(selectedEl === el || (el.contains && el.contains(selectedEl)))
|
|
5582
|
+
) {
|
|
5583
|
+
deselectElement();
|
|
5584
|
+
}
|
|
5585
|
+
el.remove();
|
|
5586
|
+
didWork = true;
|
|
5587
|
+
}
|
|
5588
|
+
} catch(_) {}
|
|
5589
|
+
}
|
|
5590
|
+
}
|
|
5591
|
+
|
|
5592
|
+
var sessionArr = sessionStructuralChainRowsByVarId[varId];
|
|
5593
|
+
if (sessionArr && sessionArr.length) {
|
|
5594
|
+
for (var i = sessionArr.length - 1; i >= 0; i--) {
|
|
5595
|
+
var row = sessionArr[i];
|
|
5596
|
+
if (!row || normalizeChangesetType(row) !== 'insert' || !row.html) continue;
|
|
5597
|
+
if (String(row.html).indexOf(needle) < 0) continue;
|
|
5598
|
+
var ts = row.vveTs;
|
|
5599
|
+
try {
|
|
5600
|
+
var k = structuralChangesetDedupKey(row);
|
|
5601
|
+
if (k) delete appliedStructuralChangesetKeys[k];
|
|
5602
|
+
} catch(_) {}
|
|
5603
|
+
sessionArr.splice(i, 1);
|
|
5604
|
+
removeStructuralStateChangeByTimestamp(varId, ts);
|
|
5605
|
+
didWork = true;
|
|
5606
|
+
}
|
|
5607
|
+
}
|
|
5608
|
+
|
|
5609
|
+
var v = variations.find(function(x) { return x._id === varId; });
|
|
5610
|
+
if (v) {
|
|
5611
|
+
var saved = parseVariationChangesets(v);
|
|
5612
|
+
var savedChanged = false;
|
|
5613
|
+
for (var si = saved.length - 1; si >= 0; si--) {
|
|
5614
|
+
var entry = saved[si];
|
|
5615
|
+
if (!entry || normalizeChangesetType(entry) !== 'insert' || !entry.html) continue;
|
|
5616
|
+
if (String(entry.html).indexOf(needle) < 0) continue;
|
|
5617
|
+
try {
|
|
5618
|
+
delete appliedChangesetSnapshots[entrySnapshotKey(entry)];
|
|
5619
|
+
} catch(_) {}
|
|
5620
|
+
saved.splice(si, 1);
|
|
5621
|
+
savedChanged = true;
|
|
5622
|
+
didWork = true;
|
|
5623
|
+
}
|
|
5624
|
+
if (savedChanged && varId === activeVarId) persistActiveVariationChangesets(saved);
|
|
5625
|
+
}
|
|
5626
|
+
|
|
5627
|
+
for (var j = stateChanges.length - 1; j >= 0; j--) {
|
|
5628
|
+
var c = stateChanges[j];
|
|
5629
|
+
if (!c || !c.isStructuralLive) continue;
|
|
5630
|
+
if (normalizeChangesetType({ type: c.structuralType }) !== 'insert') continue;
|
|
5631
|
+
var match = false;
|
|
5632
|
+
try {
|
|
5633
|
+
if (c.targetEl && c.targetEl.getAttribute && c.targetEl.getAttribute('data-vve-instance') === instId) {
|
|
5634
|
+
match = true;
|
|
5635
|
+
}
|
|
5636
|
+
} catch(_) {}
|
|
5637
|
+
if (match) {
|
|
5638
|
+
stateChanges.splice(j, 1);
|
|
5639
|
+
didWork = true;
|
|
5640
|
+
}
|
|
5641
|
+
}
|
|
5642
|
+
|
|
5643
|
+
return didWork;
|
|
4522
5644
|
}
|
|
4523
5645
|
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
if (!
|
|
4527
|
-
|
|
4528
|
-
|
|
5646
|
+
/** Live DOM nodes inserted via the visual editor, ordered by changeset/session insert order. */
|
|
5647
|
+
function collectEditorInsertedElements(doc) {
|
|
5648
|
+
if (!doc || !doc.body) return [];
|
|
5649
|
+
var byInst = {};
|
|
5650
|
+
var els;
|
|
5651
|
+
try {
|
|
5652
|
+
els = doc.querySelectorAll('[data-vve-instance]');
|
|
5653
|
+
} catch(_) {
|
|
5654
|
+
els = [];
|
|
5655
|
+
}
|
|
5656
|
+
for (var i = 0; i < els.length; i++) {
|
|
5657
|
+
var el = els[i];
|
|
5658
|
+
if (!el || el.nodeType !== 1) continue;
|
|
5659
|
+
var inst = el.getAttribute('data-vve-instance');
|
|
5660
|
+
if (inst && String(inst).trim()) byInst[String(inst)] = el;
|
|
4529
5661
|
}
|
|
4530
|
-
}
|
|
4531
5662
|
|
|
4532
|
-
|
|
4533
|
-
var
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
if (
|
|
4538
|
-
|
|
5663
|
+
var ordered = [];
|
|
5664
|
+
var seen = {};
|
|
5665
|
+
function addEl(el) {
|
|
5666
|
+
if (!el || !el.isConnected) return;
|
|
5667
|
+
var k = el.getAttribute && el.getAttribute('data-vve-instance');
|
|
5668
|
+
if (!k || seen[k]) return;
|
|
5669
|
+
seen[k] = true;
|
|
5670
|
+
ordered.push(el);
|
|
4539
5671
|
}
|
|
4540
|
-
|
|
5672
|
+
|
|
5673
|
+
if (activeVarId) {
|
|
5674
|
+
var variation = variations.find(function(v) { return v._id === activeVarId; });
|
|
5675
|
+
if (variation) {
|
|
5676
|
+
var cs = buildPersistedChainSetsForVariation(variation);
|
|
5677
|
+
for (var j = 0; j < cs.length; j++) {
|
|
5678
|
+
var row = cs[j];
|
|
5679
|
+
if (normalizeChangesetType(row) !== 'insert') continue;
|
|
5680
|
+
var instId = instanceIdFromInsertHtml(row.html);
|
|
5681
|
+
if (instId && byInst[instId]) addEl(byInst[instId]);
|
|
5682
|
+
}
|
|
5683
|
+
}
|
|
5684
|
+
}
|
|
5685
|
+
return ordered;
|
|
4541
5686
|
}
|
|
4542
5687
|
|
|
4543
5688
|
function renderElementsTree(filterRaw) {
|
|
@@ -4547,14 +5692,10 @@ function renderElementsTree(filterRaw) {
|
|
|
4547
5692
|
var iframe = document.getElementById('iframeId');
|
|
4548
5693
|
var doc = iframe && iframe.contentDocument;
|
|
4549
5694
|
if (!isIframeDomReady(iframe, doc)) {
|
|
4550
|
-
root.innerHTML = '<div class="dt-muted">Load a page to see
|
|
5695
|
+
root.innerHTML = '<div class="dt-muted">Load a page to see added elements.</div>';
|
|
4551
5696
|
return;
|
|
4552
5697
|
}
|
|
4553
5698
|
|
|
4554
|
-
function skippable(el) {
|
|
4555
|
-
return isDomTreeSkippableTagName(el.tagName);
|
|
4556
|
-
}
|
|
4557
|
-
|
|
4558
5699
|
function nodeIcon(tag) {
|
|
4559
5700
|
tag = (tag || '').toLowerCase();
|
|
4560
5701
|
if (/^h[1-6]$/.test(tag)) return 'bi bi-type-h1';
|
|
@@ -4574,50 +5715,10 @@ function renderElementsTree(filterRaw) {
|
|
|
4574
5715
|
return tag.toUpperCase();
|
|
4575
5716
|
}
|
|
4576
5717
|
|
|
4577
|
-
|
|
4578
|
-
if (!el || el.nodeType !== 1) return false;
|
|
4579
|
-
if (skippable(el)) return false;
|
|
4580
|
-
var tag = (el.tagName || '').toLowerCase();
|
|
4581
|
-
if (tag !== 'svg') {
|
|
4582
|
-
var p = el.parentElement;
|
|
4583
|
-
while (p) {
|
|
4584
|
-
if ((p.tagName || '').toLowerCase() === 'svg') return false;
|
|
4585
|
-
p = p.parentElement;
|
|
4586
|
-
}
|
|
4587
|
-
}
|
|
4588
|
-
return true;
|
|
4589
|
-
}
|
|
4590
|
-
|
|
4591
|
-
var nodes = [];
|
|
4592
|
-
var i, cursor;
|
|
4593
|
-
try {
|
|
4594
|
-
cursor = doc.createTreeWalker(doc.body, NodeFilter.SHOW_ELEMENT, null);
|
|
4595
|
-
} catch(_) {
|
|
4596
|
-
cursor = null;
|
|
4597
|
-
}
|
|
4598
|
-
if (cursor) {
|
|
4599
|
-
while (cursor.nextNode()) {
|
|
4600
|
-
var node = cursor.currentNode;
|
|
4601
|
-
if (isListableNode(node)) nodes.push(node);
|
|
4602
|
-
if (nodes.length > 4000) break;
|
|
4603
|
-
}
|
|
4604
|
-
} else {
|
|
4605
|
-
function collectFlat(el) {
|
|
4606
|
-
if (!el || !el.children) return;
|
|
4607
|
-
for (var j = 0; j < el.children.length; j++) {
|
|
4608
|
-
var c = el.children[j];
|
|
4609
|
-
if (!isListableNode(c)) continue;
|
|
4610
|
-
nodes.push(c);
|
|
4611
|
-
if (nodes.length > 4000) return;
|
|
4612
|
-
collectFlat(c);
|
|
4613
|
-
if (nodes.length > 4000) return;
|
|
4614
|
-
}
|
|
4615
|
-
}
|
|
4616
|
-
collectFlat(doc.body);
|
|
4617
|
-
}
|
|
5718
|
+
var nodes = collectEditorInsertedElements(doc);
|
|
4618
5719
|
|
|
4619
5720
|
root.innerHTML = '';
|
|
4620
|
-
for (i = 0; i < nodes.length; i++) {
|
|
5721
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
4621
5722
|
var el = nodes[i];
|
|
4622
5723
|
var lblText = labelFor(el);
|
|
4623
5724
|
if (filterText && lblText.toLowerCase().indexOf(filterText) < 0) continue;
|
|
@@ -4655,14 +5756,39 @@ function renderElementsTree(filterRaw) {
|
|
|
4655
5756
|
|
|
4656
5757
|
if (!root.querySelector('.dt-row')) {
|
|
4657
5758
|
root.innerHTML = filterText
|
|
4658
|
-
? '<div class="dt-muted">No elements match your search.</div>'
|
|
4659
|
-
: '<div class="dt-muted">No elements
|
|
5759
|
+
? '<div class="dt-muted">No added elements match your search.</div>'
|
|
5760
|
+
: '<div class="dt-muted">No elements added yet. Use Components or Sections to insert.</div>';
|
|
4660
5761
|
}
|
|
4661
5762
|
root.onmouseleave = function() {
|
|
4662
5763
|
clearTreeHoverHighlight();
|
|
4663
5764
|
};
|
|
4664
5765
|
}
|
|
4665
5766
|
|
|
5767
|
+
function domTreeLabelSuffix(el) {
|
|
5768
|
+
if (el.id != null && el.id !== '') return '#' + String(el.id).slice(0, 40);
|
|
5769
|
+
var cn = el.className && typeof el.className === 'string' ? el.className.trim() : '';
|
|
5770
|
+
if (cn) {
|
|
5771
|
+
var parts = cn.split(/s+/).filter(function(x) { return x.indexOf('vve-') !== 0; }).slice(0, 2).join('.');
|
|
5772
|
+
if (parts) return '.' + parts.slice(0, 56);
|
|
5773
|
+
}
|
|
5774
|
+
return '';
|
|
5775
|
+
}
|
|
5776
|
+
|
|
5777
|
+
function domTreeLabelFor(el) {
|
|
5778
|
+
return (el.tagName || '').toLowerCase() + domTreeLabelSuffix(el);
|
|
5779
|
+
}
|
|
5780
|
+
|
|
5781
|
+
function setDomTreeLabelContent(lbl, el) {
|
|
5782
|
+
var tag = (el.tagName || '').toLowerCase();
|
|
5783
|
+
lbl.textContent = '';
|
|
5784
|
+
var tagSpan = document.createElement('span');
|
|
5785
|
+
tagSpan.className = 'dt-tag';
|
|
5786
|
+
tagSpan.textContent = tag;
|
|
5787
|
+
lbl.appendChild(tagSpan);
|
|
5788
|
+
var suffix = domTreeLabelSuffix(el);
|
|
5789
|
+
if (suffix) lbl.appendChild(document.createTextNode(suffix));
|
|
5790
|
+
}
|
|
5791
|
+
|
|
4666
5792
|
function renderDomTree(filterRaw) {
|
|
4667
5793
|
var filterText = (filterRaw || '').toLowerCase().trim();
|
|
4668
5794
|
var root = document.getElementById('dom-tree-root');
|
|
@@ -4680,14 +5806,7 @@ function renderDomTree(filterRaw) {
|
|
|
4680
5806
|
}
|
|
4681
5807
|
|
|
4682
5808
|
function labelFor(el) {
|
|
4683
|
-
|
|
4684
|
-
if (el.id != null && el.id !== '') return tag + '#' + String(el.id).slice(0, 40);
|
|
4685
|
-
var cn = el.className && typeof el.className === 'string' ? el.className.trim() : '';
|
|
4686
|
-
if (cn) {
|
|
4687
|
-
var parts = cn.split(/s+/).filter(function(x) { return x.indexOf('vve-') !== 0; }).slice(0, 2).join('.');
|
|
4688
|
-
if (parts) return tag + '.' + parts.slice(0, 56);
|
|
4689
|
-
}
|
|
4690
|
-
return tag;
|
|
5809
|
+
return domTreeLabelFor(el);
|
|
4691
5810
|
}
|
|
4692
5811
|
|
|
4693
5812
|
function skippable(el) {
|
|
@@ -4764,7 +5883,7 @@ function renderDomTree(filterRaw) {
|
|
|
4764
5883
|
|
|
4765
5884
|
var lbl = document.createElement('div');
|
|
4766
5885
|
lbl.className = 'dt-lbl';
|
|
4767
|
-
lbl
|
|
5886
|
+
setDomTreeLabelContent(lbl, el);
|
|
4768
5887
|
lbl.title = buildSelector(el);
|
|
4769
5888
|
|
|
4770
5889
|
row.appendChild(chev);
|
|
@@ -4815,6 +5934,203 @@ function pr2(l1, i1, l2, i2) {
|
|
|
4815
5934
|
'<div class="pr2-item"><div class="pr2-lbl">'+l2+'</div>'+i2+'</div></div>';
|
|
4816
5935
|
}
|
|
4817
5936
|
function subLbl(text) { return '<div class="sub-lbl">'+text+'</div>'; }
|
|
5937
|
+
|
|
5938
|
+
function isLinkElement(el) {
|
|
5939
|
+
if (!el || el.nodeType !== 1) return false;
|
|
5940
|
+
var tag = (el.tagName || '').toLowerCase();
|
|
5941
|
+
if (tag === 'a') return true;
|
|
5942
|
+
try {
|
|
5943
|
+
return el.getAttribute && el.getAttribute('role') === 'link';
|
|
5944
|
+
} catch(_) {}
|
|
5945
|
+
return false;
|
|
5946
|
+
}
|
|
5947
|
+
|
|
5948
|
+
function isFormControlElement(el) {
|
|
5949
|
+
if (!el || el.nodeType !== 1) return false;
|
|
5950
|
+
var tag = (el.tagName || '').toLowerCase();
|
|
5951
|
+
return tag === 'input' || tag === 'textarea' || tag === 'select';
|
|
5952
|
+
}
|
|
5953
|
+
|
|
5954
|
+
function shouldShowInnerContentFields(el) {
|
|
5955
|
+
if (!el || el.nodeType !== 1) return false;
|
|
5956
|
+
var tag = (el.tagName || '').toLowerCase();
|
|
5957
|
+
if (tag === 'input' || tag === 'textarea' || tag === 'video') return false;
|
|
5958
|
+
if (isEmbeddedVideoIframe(el)) return false;
|
|
5959
|
+
return true;
|
|
5960
|
+
}
|
|
5961
|
+
|
|
5962
|
+
function elementHasHtmlChildren(el) {
|
|
5963
|
+
if (!el || el.nodeType !== 1) return false;
|
|
5964
|
+
try {
|
|
5965
|
+
var nodes = el.childNodes;
|
|
5966
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
5967
|
+
if (nodes[i].nodeType === 1) return true;
|
|
5968
|
+
}
|
|
5969
|
+
} catch(_) {}
|
|
5970
|
+
return false;
|
|
5971
|
+
}
|
|
5972
|
+
|
|
5973
|
+
function getFormControlValue(el) {
|
|
5974
|
+
if (!isFormControlElement(el)) return '';
|
|
5975
|
+
try {
|
|
5976
|
+
return el.value != null ? String(el.value) : '';
|
|
5977
|
+
} catch(_) {
|
|
5978
|
+
return '';
|
|
5979
|
+
}
|
|
5980
|
+
}
|
|
5981
|
+
|
|
5982
|
+
function getVideoSrc(el) {
|
|
5983
|
+
if (!el || el.nodeType !== 1) return '';
|
|
5984
|
+
try {
|
|
5985
|
+
var source = el.querySelector && el.querySelector('source');
|
|
5986
|
+
if (source && source.getAttribute('src')) return source.getAttribute('src') || '';
|
|
5987
|
+
return el.getAttribute('src') || '';
|
|
5988
|
+
} catch(_) {
|
|
5989
|
+
return '';
|
|
5990
|
+
}
|
|
5991
|
+
}
|
|
5992
|
+
|
|
5993
|
+
function setVideoSrc(el, value) {
|
|
5994
|
+
if (!el || el.nodeType !== 1) return;
|
|
5995
|
+
var v = value == null ? '' : String(value);
|
|
5996
|
+
try {
|
|
5997
|
+
var source = el.querySelector && el.querySelector('source');
|
|
5998
|
+
if (source) {
|
|
5999
|
+
if (v) source.setAttribute('src', v);
|
|
6000
|
+
else source.removeAttribute('src');
|
|
6001
|
+
} else if (v) {
|
|
6002
|
+
el.setAttribute('src', v);
|
|
6003
|
+
} else {
|
|
6004
|
+
el.removeAttribute('src');
|
|
6005
|
+
}
|
|
6006
|
+
try {
|
|
6007
|
+
el.load();
|
|
6008
|
+
} catch(_) {}
|
|
6009
|
+
} catch(_) {}
|
|
6010
|
+
}
|
|
6011
|
+
|
|
6012
|
+
function isYoutubeVideoElement(el) {
|
|
6013
|
+
if (!el || el.nodeType !== 1) return false;
|
|
6014
|
+
if ((el.tagName || '').toLowerCase() !== 'iframe') return false;
|
|
6015
|
+
if (el.hasAttribute && el.hasAttribute('data-youtube-id')) return true;
|
|
6016
|
+
var src = el.getAttribute('src') || '';
|
|
6017
|
+
return src.indexOf('youtube.com/embed/') !== -1 || src.indexOf('youtu.be/') !== -1;
|
|
6018
|
+
}
|
|
6019
|
+
|
|
6020
|
+
function normalizeYoutubeVideoId(input) {
|
|
6021
|
+
var raw = String(input || '').trim();
|
|
6022
|
+
if (!raw) return '';
|
|
6023
|
+
var m = raw.match(new RegExp('(?:youtube\\.com/(?:embed/|watch\\?(?:.*&)?v=|shorts/|live/)|youtu\\.be/)([A-Za-z0-9_-]{11})', 'i'));
|
|
6024
|
+
if (m) return m[1];
|
|
6025
|
+
var bare = raw.match(/^([A-Za-z0-9_-]{11})$/);
|
|
6026
|
+
return bare ? bare[1] : raw;
|
|
6027
|
+
}
|
|
6028
|
+
|
|
6029
|
+
function getYoutubeVideoId(el) {
|
|
6030
|
+
if (!isYoutubeVideoElement(el)) return '';
|
|
6031
|
+
try {
|
|
6032
|
+
var explicit = el.getAttribute('data-youtube-id');
|
|
6033
|
+
if (explicit != null && String(explicit).trim()) return String(explicit).trim();
|
|
6034
|
+
var src = el.getAttribute('src') || '';
|
|
6035
|
+
var m = src.match(new RegExp('(?:youtube\\.com/embed/|youtu\\.be/)([A-Za-z0-9_-]{11})', 'i'));
|
|
6036
|
+
return m ? m[1] : '';
|
|
6037
|
+
} catch(_) {
|
|
6038
|
+
return '';
|
|
6039
|
+
}
|
|
6040
|
+
}
|
|
6041
|
+
|
|
6042
|
+
function setYoutubeVideoId(el, value) {
|
|
6043
|
+
if (!el || el.nodeType !== 1) return;
|
|
6044
|
+
var id = normalizeYoutubeVideoId(value);
|
|
6045
|
+
try {
|
|
6046
|
+
if (id) {
|
|
6047
|
+
el.setAttribute('data-youtube-id', id);
|
|
6048
|
+
el.setAttribute('src', 'https://www.youtube.com/embed/' + id);
|
|
6049
|
+
} else {
|
|
6050
|
+
el.removeAttribute('data-youtube-id');
|
|
6051
|
+
el.setAttribute('src', 'about:blank');
|
|
6052
|
+
}
|
|
6053
|
+
} catch(_) {}
|
|
6054
|
+
}
|
|
6055
|
+
|
|
6056
|
+
function isVimeoVideoElement(el) {
|
|
6057
|
+
if (!el || el.nodeType !== 1) return false;
|
|
6058
|
+
if ((el.tagName || '').toLowerCase() !== 'iframe') return false;
|
|
6059
|
+
if (el.hasAttribute && el.hasAttribute('data-vimeo-id')) return true;
|
|
6060
|
+
var src = el.getAttribute('src') || '';
|
|
6061
|
+
return src.indexOf('player.vimeo.com/video/') !== -1 || src.indexOf('vimeo.com/video/') !== -1;
|
|
6062
|
+
}
|
|
6063
|
+
|
|
6064
|
+
function isEmbeddedVideoIframe(el) {
|
|
6065
|
+
return isYoutubeVideoElement(el) || isVimeoVideoElement(el);
|
|
6066
|
+
}
|
|
6067
|
+
|
|
6068
|
+
function normalizeVimeoVideoId(input) {
|
|
6069
|
+
var raw = String(input || '').trim();
|
|
6070
|
+
if (!raw) return '';
|
|
6071
|
+
var m = raw.match(new RegExp('(?:player\\.vimeo\\.com/video/|vimeo\\.com/(?:video/)?)([0-9]+)', 'i'));
|
|
6072
|
+
if (m) return m[1];
|
|
6073
|
+
var bare = raw.match(/^([0-9]+)$/);
|
|
6074
|
+
return bare ? bare[1] : raw.replace(/[^d]/g, '');
|
|
6075
|
+
}
|
|
6076
|
+
|
|
6077
|
+
function getVimeoVideoId(el) {
|
|
6078
|
+
if (!isVimeoVideoElement(el)) return '';
|
|
6079
|
+
try {
|
|
6080
|
+
var explicit = el.getAttribute('data-vimeo-id');
|
|
6081
|
+
if (explicit != null && String(explicit).trim()) return String(explicit).trim();
|
|
6082
|
+
var src = el.getAttribute('src') || '';
|
|
6083
|
+
var m = src.match(new RegExp('(?:player\\.vimeo\\.com/video/|vimeo\\.com/video/)([0-9]+)', 'i'));
|
|
6084
|
+
return m ? m[1] : '';
|
|
6085
|
+
} catch(_) {
|
|
6086
|
+
return '';
|
|
6087
|
+
}
|
|
6088
|
+
}
|
|
6089
|
+
|
|
6090
|
+
function setVimeoVideoId(el, value) {
|
|
6091
|
+
if (!el || el.nodeType !== 1) return;
|
|
6092
|
+
var id = normalizeVimeoVideoId(value);
|
|
6093
|
+
try {
|
|
6094
|
+
if (id) {
|
|
6095
|
+
el.setAttribute('data-vimeo-id', id);
|
|
6096
|
+
el.setAttribute('src', 'https://player.vimeo.com/video/' + id);
|
|
6097
|
+
} else {
|
|
6098
|
+
el.removeAttribute('data-vimeo-id');
|
|
6099
|
+
el.setAttribute('src', 'about:blank');
|
|
6100
|
+
}
|
|
6101
|
+
} catch(_) {}
|
|
6102
|
+
}
|
|
6103
|
+
|
|
6104
|
+
function buildAnchorContentFieldsHtml(el) {
|
|
6105
|
+
return (
|
|
6106
|
+
subLbl('Link attributes') +
|
|
6107
|
+
pr('Href', '<input class="pr-inp" id="pp-href" type="text" value="'+esc(el.getAttribute('href')||'')+'" placeholder="https:// or #section">') +
|
|
6108
|
+
pr2(
|
|
6109
|
+
'Target',
|
|
6110
|
+
'<select class="pr-inp" id="pp-target">'+selOpts(['','_self','_blank','_parent','_top'],el.getAttribute('target')||'')+'</select>',
|
|
6111
|
+
'Rel',
|
|
6112
|
+
'<input class="pr-inp" id="pp-rel" type="text" value="'+esc(el.getAttribute('rel')||'')+'" placeholder="noopener noreferrer">'
|
|
6113
|
+
) +
|
|
6114
|
+
pr('Title', '<input class="pr-inp" id="pp-link-title" type="text" value="'+esc(el.getAttribute('title')||'')+'">') +
|
|
6115
|
+
pr2(
|
|
6116
|
+
'Hreflang',
|
|
6117
|
+
'<input class="pr-inp" id="pp-hreflang" type="text" value="'+esc(el.getAttribute('hreflang')||'')+'" placeholder="en">',
|
|
6118
|
+
'Type',
|
|
6119
|
+
'<input class="pr-inp" id="pp-link-type" type="text" value="'+esc(el.getAttribute('type')||'')+'" placeholder="MIME type">'
|
|
6120
|
+
) +
|
|
6121
|
+
pr(
|
|
6122
|
+
'Referrer policy',
|
|
6123
|
+
'<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>'
|
|
6124
|
+
)
|
|
6125
|
+
);
|
|
6126
|
+
}
|
|
6127
|
+
|
|
6128
|
+
function setOptionalAnchorAttr(el, name, value) {
|
|
6129
|
+
if (!el || !name) return;
|
|
6130
|
+
var v = value == null ? '' : String(value).trim();
|
|
6131
|
+
if (v) el.setAttribute(name, v);
|
|
6132
|
+
else el.removeAttribute(name);
|
|
6133
|
+
}
|
|
4818
6134
|
function openCustomCssModal() {
|
|
4819
6135
|
var modal = document.getElementById('custom-css-modal');
|
|
4820
6136
|
var ta = document.getElementById('custom-css-modal-textarea');
|
|
@@ -5015,8 +6331,122 @@ function removeSizesEntry(i) {
|
|
|
5015
6331
|
}
|
|
5016
6332
|
}
|
|
5017
6333
|
|
|
6334
|
+
// \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
|
|
6335
|
+
var _videoEl = null;
|
|
6336
|
+
|
|
6337
|
+
function renderVideoSection(el) {
|
|
6338
|
+
_videoEl = el;
|
|
6339
|
+
var sel = buildSelector(el);
|
|
6340
|
+
var src = getVideoSrc(el);
|
|
6341
|
+
var html = '';
|
|
6342
|
+
|
|
6343
|
+
if (src) {
|
|
6344
|
+
html += '<video class="video-preview" src="'+esc(src)+'" controls muted></video>';
|
|
6345
|
+
}
|
|
6346
|
+
|
|
6347
|
+
html += pr('Src', '<input class="pr-inp" id="pp-video-src" type="url" value="'+esc(src)+'" placeholder="https://example.com/video.mp4">');
|
|
6348
|
+
html += pr('Poster', '<input class="pr-inp" id="pp-video-poster" type="url" value="'+esc(el.getAttribute('poster')||'')+'" placeholder="https://\u2026">');
|
|
6349
|
+
|
|
6350
|
+
document.getElementById('acc-body-video').innerHTML = html;
|
|
6351
|
+
|
|
6352
|
+
var srcInp = document.getElementById('pp-video-src');
|
|
6353
|
+
if (srcInp) srcInp.addEventListener('input', function() {
|
|
6354
|
+
var orig = getOriginalValue('pp-video-src', el);
|
|
6355
|
+
setVideoSrc(el, srcInp.value);
|
|
6356
|
+
var prev = document.querySelector('.video-preview');
|
|
6357
|
+
if (prev) {
|
|
6358
|
+
prev.src = srcInp.value;
|
|
6359
|
+
prev.style.display = srcInp.value ? '' : 'none';
|
|
6360
|
+
} else if (srcInp.value) {
|
|
6361
|
+
renderVideoSection(el);
|
|
6362
|
+
}
|
|
6363
|
+
logChange(sel, 'pp-video-src', srcInp.value, el, orig);
|
|
6364
|
+
});
|
|
6365
|
+
var posterInp = document.getElementById('pp-video-poster');
|
|
6366
|
+
if (posterInp) posterInp.addEventListener('input', function() {
|
|
6367
|
+
var orig = el.getAttribute('poster') || '';
|
|
6368
|
+
if (posterInp.value) el.setAttribute('poster', posterInp.value);
|
|
6369
|
+
else el.removeAttribute('poster');
|
|
6370
|
+
var prev = document.querySelector('.video-preview');
|
|
6371
|
+
if (prev) prev.poster = posterInp.value;
|
|
6372
|
+
logChange(sel, 'pp-video-poster', posterInp.value, el, orig);
|
|
6373
|
+
});
|
|
6374
|
+
}
|
|
6375
|
+
|
|
6376
|
+
// \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
|
|
6377
|
+
var _youtubeEl = null;
|
|
6378
|
+
var _vimeoEl = null;
|
|
6379
|
+
|
|
6380
|
+
function renderYoutubeSection(el) {
|
|
6381
|
+
_youtubeEl = el;
|
|
6382
|
+
var sel = buildSelector(el);
|
|
6383
|
+
var id = getYoutubeVideoId(el);
|
|
6384
|
+
var html = '';
|
|
6385
|
+
|
|
6386
|
+
if (id) {
|
|
6387
|
+
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>';
|
|
6388
|
+
}
|
|
6389
|
+
|
|
6390
|
+
html += pr('YouTube video ID', '<input class="pr-inp" id="pp-youtube-id" type="text" value="'+esc(id)+'" placeholder="dQw4w9WgXcQ">');
|
|
6391
|
+
|
|
6392
|
+
document.getElementById('acc-body-youtube').innerHTML = html;
|
|
6393
|
+
|
|
6394
|
+
var idInp = document.getElementById('pp-youtube-id');
|
|
6395
|
+
if (idInp) idInp.addEventListener('input', function() {
|
|
6396
|
+
var orig = getOriginalValue('pp-youtube-id', el);
|
|
6397
|
+
setYoutubeVideoId(el, idInp.value);
|
|
6398
|
+
var normalized = normalizeYoutubeVideoId(idInp.value);
|
|
6399
|
+
var prev = document.querySelector('#acc-body-youtube .embed-preview');
|
|
6400
|
+
if (prev) {
|
|
6401
|
+
if (normalized) {
|
|
6402
|
+
prev.src = 'https://www.youtube.com/embed/' + normalized;
|
|
6403
|
+
prev.style.display = '';
|
|
6404
|
+
} else {
|
|
6405
|
+
prev.style.display = 'none';
|
|
6406
|
+
}
|
|
6407
|
+
} else if (normalized) {
|
|
6408
|
+
renderYoutubeSection(el);
|
|
6409
|
+
}
|
|
6410
|
+
logChange(sel, 'pp-youtube-id', idInp.value, el, orig);
|
|
6411
|
+
});
|
|
6412
|
+
}
|
|
6413
|
+
|
|
6414
|
+
function renderVimeoSection(el) {
|
|
6415
|
+
_vimeoEl = el;
|
|
6416
|
+
var sel = buildSelector(el);
|
|
6417
|
+
var id = getVimeoVideoId(el);
|
|
6418
|
+
var html = '';
|
|
6419
|
+
|
|
6420
|
+
if (id) {
|
|
6421
|
+
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>';
|
|
6422
|
+
}
|
|
6423
|
+
|
|
6424
|
+
html += pr('Vimeo video ID', '<input class="pr-inp" id="pp-vimeo-id" type="text" value="'+esc(id)+'" placeholder="76979871">');
|
|
6425
|
+
|
|
6426
|
+
document.getElementById('acc-body-vimeo').innerHTML = html;
|
|
6427
|
+
|
|
6428
|
+
var idInp = document.getElementById('pp-vimeo-id');
|
|
6429
|
+
if (idInp) idInp.addEventListener('input', function() {
|
|
6430
|
+
var orig = getOriginalValue('pp-vimeo-id', el);
|
|
6431
|
+
setVimeoVideoId(el, idInp.value);
|
|
6432
|
+
var normalized = normalizeVimeoVideoId(idInp.value);
|
|
6433
|
+
var prev = document.querySelector('#acc-body-vimeo .embed-preview');
|
|
6434
|
+
if (prev) {
|
|
6435
|
+
if (normalized) {
|
|
6436
|
+
prev.src = 'https://player.vimeo.com/video/' + normalized;
|
|
6437
|
+
prev.style.display = '';
|
|
6438
|
+
} else {
|
|
6439
|
+
prev.style.display = 'none';
|
|
6440
|
+
}
|
|
6441
|
+
} else if (normalized) {
|
|
6442
|
+
renderVimeoSection(el);
|
|
6443
|
+
}
|
|
6444
|
+
logChange(sel, 'pp-vimeo-id', idInp.value, el, orig);
|
|
6445
|
+
});
|
|
6446
|
+
}
|
|
6447
|
+
|
|
5018
6448
|
// \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
|
|
5019
|
-
function renderRightPanel(el) {
|
|
6449
|
+
function renderRightPanel(el, options) {
|
|
5020
6450
|
if (!el) return;
|
|
5021
6451
|
var cs = el.ownerDocument.defaultView.getComputedStyle(el);
|
|
5022
6452
|
var tag = el.tagName.toLowerCase();
|
|
@@ -5027,20 +6457,54 @@ function renderRightPanel(el) {
|
|
|
5027
6457
|
document.getElementById('el-info').style.display = '';
|
|
5028
6458
|
document.getElementById('rp-accordion').style.display = '';
|
|
5029
6459
|
|
|
5030
|
-
// \u2500\u2500 Image
|
|
6460
|
+
// \u2500\u2500 Image / video accordions (show matching section at top) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5031
6461
|
var imgSec = document.getElementById('acc-image');
|
|
5032
6462
|
if (tag === 'img') {
|
|
5033
6463
|
imgSec.style.display = '';
|
|
5034
|
-
if (!imgSec.classList.contains('open')) imgSec.classList.add('open');
|
|
5035
6464
|
renderImageSection(el);
|
|
5036
6465
|
} else {
|
|
5037
6466
|
imgSec.style.display = 'none';
|
|
6467
|
+
imgSec.classList.remove('open');
|
|
5038
6468
|
_imageEl = null;
|
|
5039
6469
|
}
|
|
5040
6470
|
|
|
6471
|
+
var videoSec = document.getElementById('acc-video');
|
|
6472
|
+
if (tag === 'video') {
|
|
6473
|
+
videoSec.style.display = '';
|
|
6474
|
+
renderVideoSection(el);
|
|
6475
|
+
} else {
|
|
6476
|
+
videoSec.style.display = 'none';
|
|
6477
|
+
videoSec.classList.remove('open');
|
|
6478
|
+
_videoEl = null;
|
|
6479
|
+
}
|
|
6480
|
+
|
|
6481
|
+
var youtubeSec = document.getElementById('acc-youtube');
|
|
6482
|
+
if (isYoutubeVideoElement(el)) {
|
|
6483
|
+
youtubeSec.style.display = '';
|
|
6484
|
+
renderYoutubeSection(el);
|
|
6485
|
+
} else {
|
|
6486
|
+
youtubeSec.style.display = 'none';
|
|
6487
|
+
youtubeSec.classList.remove('open');
|
|
6488
|
+
_youtubeEl = null;
|
|
6489
|
+
}
|
|
6490
|
+
|
|
6491
|
+
var vimeoSec = document.getElementById('acc-vimeo');
|
|
6492
|
+
if (isVimeoVideoElement(el)) {
|
|
6493
|
+
vimeoSec.style.display = '';
|
|
6494
|
+
renderVimeoSection(el);
|
|
6495
|
+
} else {
|
|
6496
|
+
vimeoSec.style.display = 'none';
|
|
6497
|
+
vimeoSec.classList.remove('open');
|
|
6498
|
+
_vimeoEl = null;
|
|
6499
|
+
}
|
|
6500
|
+
|
|
6501
|
+
var activeAccSection =
|
|
6502
|
+
(options && options.preferredAccSection) ||
|
|
6503
|
+
getTypeDefaultAccSection(el);
|
|
6504
|
+
|
|
5041
6505
|
// \u2500\u2500 Typography \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5042
6506
|
document.getElementById('acc-body-typography').innerHTML =
|
|
5043
|
-
pr('Color', '<input type="color" class="pr-color" id="pp-color" value="'+esc(rgbToHex(cs.color))+'"><span style="font-size:11px;color:var(--text-3);flex:1;font-family:
|
|
6507
|
+
pr('Color', '<input type="color" class="pr-color" id="pp-color" value="'+esc(rgbToHex(cs.color))+'"><span style="font-size:11px;color:var(--text-3);flex:1;font-family:var(--font-mono)">'+esc(cs.color)+'</span>') +
|
|
5044
6508
|
pr2('Font size', '<input class="pr-inp" type="number" id="pp-fs" min="8" max="200" value="'+parseInt(cs.fontSize||'16')+'">',
|
|
5045
6509
|
'Font weight', '<select class="pr-inp" id="pp-fw">'+weightOpts(cs.fontWeight)+'</select>') +
|
|
5046
6510
|
pr('Font family', '<input class="pr-inp" id="pp-ff" type="text" value="'+esc(el.style.fontFamily||'')+'" placeholder="inherit">') +
|
|
@@ -5052,7 +6516,7 @@ function renderRightPanel(el) {
|
|
|
5052
6516
|
// \u2500\u2500 Background \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5053
6517
|
var bgiVal = (el.style.backgroundImage||'').replace(/url(['"]?([^'"]+)['"]?)/,'$1');
|
|
5054
6518
|
document.getElementById('acc-body-background').innerHTML =
|
|
5055
|
-
pr('Color', '<input type="color" class="pr-color" id="pp-bg" value="'+esc(rgbToHex(cs.backgroundColor))+'"><span style="font-size:11px;color:var(--text-3);flex:1;font-family:
|
|
6519
|
+
pr('Color', '<input type="color" class="pr-color" id="pp-bg" value="'+esc(rgbToHex(cs.backgroundColor))+'"><span style="font-size:11px;color:var(--text-3);flex:1;font-family:var(--font-mono)">'+esc(cs.backgroundColor)+'</span>') +
|
|
5056
6520
|
pr('Image URL', '<input class="pr-inp" id="pp-bgi" type="url" value="'+esc(bgiVal)+'" placeholder="https://\u2026">') +
|
|
5057
6521
|
pr2('Size', '<select class="pr-inp" id="pp-bgs">'+selOpts(['auto','cover','contain'],el.style.backgroundSize||'auto')+'</select>',
|
|
5058
6522
|
'Repeat', '<select class="pr-inp" id="pp-bgr">'+selOpts(['repeat','no-repeat','repeat-x','repeat-y'],el.style.backgroundRepeat||'repeat')+'</select>');
|
|
@@ -5122,9 +6586,9 @@ function renderRightPanel(el) {
|
|
|
5122
6586
|
// \u2500\u2500 Device styling rules \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5123
6587
|
document.getElementById('acc-body-device').innerHTML =
|
|
5124
6588
|
subLbl('Mobile (\u2264768px)') +
|
|
5125
|
-
'<textarea class="pr-inp" id="pp-mob-css" style="width:100%;min-height:60px;font-family:
|
|
6589
|
+
'<textarea class="pr-inp" id="pp-mob-css" style="width:100%;min-height:60px;font-family:var(--font-mono);font-size:11px;margin-bottom:8px" placeholder="/* styles for mobile */">'+esc(el.dataset.mobileCss||'')+'</textarea>' +
|
|
5126
6590
|
subLbl('Tablet (\u22641024px)') +
|
|
5127
|
-
'<textarea class="pr-inp" id="pp-tab-css" style="width:100%;min-height:60px;font-family:
|
|
6591
|
+
'<textarea class="pr-inp" id="pp-tab-css" style="width:100%;min-height:60px;font-family:var(--font-mono);font-size:11px" placeholder="/* styles for tablet */">'+esc(el.dataset.tabletCss||'')+'</textarea>';
|
|
5128
6592
|
|
|
5129
6593
|
// \u2500\u2500 CSS and Classes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5130
6594
|
document.getElementById('acc-body-css').innerHTML =
|
|
@@ -5135,27 +6599,41 @@ function renderRightPanel(el) {
|
|
|
5135
6599
|
'<i class="bi bi-fullscreen"></i>' +
|
|
5136
6600
|
'</button>' +
|
|
5137
6601
|
'</div>' +
|
|
5138
|
-
'<textarea class="pr-inp" id="pp-css" style="width:100%;min-height:80px;font-family:
|
|
6602
|
+
'<textarea class="pr-inp" id="pp-css" style="width:100%;min-height:80px;font-family:var(--font-mono);font-size:11px" placeholder="color: red; font-size: 16px;">'+esc(el.getAttribute('style')||'')+'</textarea>';
|
|
5139
6603
|
|
|
5140
6604
|
// \u2500\u2500 Attributes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5141
6605
|
var attrHtml =
|
|
5142
6606
|
pr('ID', '<input class="pr-inp" id="pp-id" type="text" value="'+esc(el.id||'')+'" placeholder="element-id">');
|
|
5143
|
-
if (tag==='a') attrHtml +=
|
|
5144
|
-
pr('Href', '<input class="pr-inp" id="pp-href" type="url" value="'+esc(el.getAttribute('href')||'')+'" placeholder="https://">') +
|
|
5145
|
-
pr('Target', '<select class="pr-inp" id="pp-target">'+selOpts(['','_blank','_self','_parent'],el.getAttribute('target')||'')+'</select>');
|
|
5146
6607
|
if (tag==='img') attrHtml +=
|
|
5147
6608
|
pr('Src', '<input class="pr-inp" id="pp-src" type="url" value="'+esc(el.getAttribute('src')||'')+'">') +
|
|
5148
6609
|
pr('Alt', '<input class="pr-inp" id="pp-alt" type="text" value="'+esc(el.getAttribute('alt')||'')+'">');
|
|
5149
|
-
if (tag==='input'||tag==='textarea') attrHtml +=
|
|
5150
|
-
pr('Placeholder', '<input class="pr-inp" id="pp-ph" type="text" value="'+esc(el.getAttribute('placeholder')||'')+'">');
|
|
5151
6610
|
document.getElementById('acc-body-attributes').innerHTML = attrHtml;
|
|
5152
6611
|
|
|
5153
6612
|
// \u2500\u2500 HTML Content \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
6613
|
+
var contentHtml = '';
|
|
6614
|
+
if (isLinkElement(el)) contentHtml += buildAnchorContentFieldsHtml(el);
|
|
6615
|
+
if (isFormControlElement(el)) {
|
|
6616
|
+
contentHtml +=
|
|
6617
|
+
subLbl('Value') +
|
|
6618
|
+
'<textarea class="pr-inp" id="pp-value" style="width:100%;min-height:44px;margin-bottom:8px">'+esc(getFormControlValue(el))+'</textarea>';
|
|
6619
|
+
}
|
|
6620
|
+
if (tag==='input' || tag==='textarea') {
|
|
6621
|
+
contentHtml +=
|
|
6622
|
+
subLbl('Placeholder') +
|
|
6623
|
+
'<input class="pr-inp" id="pp-ph" type="text" value="'+esc(el.getAttribute('placeholder')||'')+'" style="width:100%;margin-bottom:8px">';
|
|
6624
|
+
}
|
|
6625
|
+
if (shouldShowInnerContentFields(el)) {
|
|
6626
|
+
if (elementHasHtmlChildren(el)) {
|
|
6627
|
+
contentHtml +=
|
|
6628
|
+
subLbl('Inner HTML') +
|
|
6629
|
+
'<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>';
|
|
6630
|
+
} else {
|
|
6631
|
+
contentHtml +=
|
|
6632
|
+
subLbl('Inner Text') +
|
|
6633
|
+
'<textarea class="pr-inp" id="pp-text" style="width:100%;min-height:60px;margin-bottom:8px">'+esc(el.innerText||'')+'</textarea>';
|
|
6634
|
+
}
|
|
6635
|
+
}
|
|
6636
|
+
document.getElementById('acc-body-content').innerHTML = contentHtml;
|
|
5159
6637
|
|
|
5160
6638
|
// \u2500\u2500 Wire up all inputs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5161
6639
|
var bindings = [
|
|
@@ -5206,13 +6684,16 @@ function renderRightPanel(el) {
|
|
|
5206
6684
|
['pp-cls', function(v){el.className=v}],
|
|
5207
6685
|
['pp-css', function(v){el.setAttribute('style',v)}],
|
|
5208
6686
|
['pp-id', function(v){el.id=v}],
|
|
5209
|
-
['pp-href', function(v){el
|
|
5210
|
-
['pp-target', function(v){el
|
|
6687
|
+
['pp-href', function(v){setOptionalAnchorAttr(el,'href',v)}],
|
|
6688
|
+
['pp-target', function(v){setOptionalAnchorAttr(el,'target',v)}],
|
|
6689
|
+
['pp-rel', function(v){setOptionalAnchorAttr(el,'rel',v)}],
|
|
6690
|
+
['pp-link-title', function(v){setOptionalAnchorAttr(el,'title',v)}],
|
|
6691
|
+
['pp-hreflang', function(v){setOptionalAnchorAttr(el,'hreflang',v)}],
|
|
6692
|
+
['pp-link-type', function(v){setOptionalAnchorAttr(el,'type',v)}],
|
|
6693
|
+
['pp-referrerpolicy', function(v){setOptionalAnchorAttr(el,'referrerpolicy',v)}],
|
|
5211
6694
|
['pp-src', function(v){el.setAttribute('src',v)}],
|
|
5212
6695
|
['pp-alt', function(v){el.setAttribute('alt',v)}],
|
|
5213
6696
|
['pp-ph', function(v){el.setAttribute('placeholder',v)}],
|
|
5214
|
-
['pp-text', function(v){el.innerText=v}],
|
|
5215
|
-
['pp-html', function(v){el.innerHTML=v}],
|
|
5216
6697
|
];
|
|
5217
6698
|
var sel = buildSelector(el);
|
|
5218
6699
|
bindings.forEach(function(b){
|
|
@@ -5237,6 +6718,52 @@ function renderRightPanel(el) {
|
|
|
5237
6718
|
inp.addEventListener('change', onValueChange);
|
|
5238
6719
|
}
|
|
5239
6720
|
});
|
|
6721
|
+
wireContentFieldSync(el, sel);
|
|
6722
|
+
requestAnimationFrame(function() {
|
|
6723
|
+
requestAnimationFrame(function() {
|
|
6724
|
+
openAccSection(activeAccSection);
|
|
6725
|
+
});
|
|
6726
|
+
});
|
|
6727
|
+
}
|
|
6728
|
+
|
|
6729
|
+
function wireContentFieldSync(el, sel) {
|
|
6730
|
+
var textInp = document.getElementById('pp-text');
|
|
6731
|
+
var htmlInp = document.getElementById('pp-html');
|
|
6732
|
+
var valueInp = document.getElementById('pp-value');
|
|
6733
|
+
var syncing = false;
|
|
6734
|
+
function applyContentChange(changedId) {
|
|
6735
|
+
if (syncing) return;
|
|
6736
|
+
syncing = true;
|
|
6737
|
+
try {
|
|
6738
|
+
var orig = getOriginalValue(changedId, el);
|
|
6739
|
+
if (changedId === 'pp-value') {
|
|
6740
|
+
el.value = valueInp.value;
|
|
6741
|
+
logChange(sel, 'pp-value', valueInp.value, el, orig);
|
|
6742
|
+
} else if (changedId === 'pp-text') {
|
|
6743
|
+
el.innerText = textInp.value;
|
|
6744
|
+
if (htmlInp) htmlInp.value = el.innerHTML;
|
|
6745
|
+
logChange(sel, 'pp-text', textInp.value, el, orig);
|
|
6746
|
+
} else {
|
|
6747
|
+
el.innerHTML = htmlInp.value;
|
|
6748
|
+
if (textInp) textInp.value = el.innerText;
|
|
6749
|
+
logChange(sel, 'pp-html', htmlInp.value, el, orig);
|
|
6750
|
+
}
|
|
6751
|
+
} finally {
|
|
6752
|
+
syncing = false;
|
|
6753
|
+
}
|
|
6754
|
+
}
|
|
6755
|
+
if (valueInp && isFormControlElement(el)) {
|
|
6756
|
+
valueInp.addEventListener('input', function() { applyContentChange('pp-value'); });
|
|
6757
|
+
valueInp.addEventListener('change', function() { applyContentChange('pp-value'); });
|
|
6758
|
+
}
|
|
6759
|
+
if (textInp) {
|
|
6760
|
+
textInp.addEventListener('input', function() { applyContentChange('pp-text'); });
|
|
6761
|
+
textInp.addEventListener('change', function() { applyContentChange('pp-text'); });
|
|
6762
|
+
}
|
|
6763
|
+
if (htmlInp) {
|
|
6764
|
+
htmlInp.addEventListener('input', function() { applyContentChange('pp-html'); });
|
|
6765
|
+
htmlInp.addEventListener('change', function() { applyContentChange('pp-html'); });
|
|
6766
|
+
}
|
|
5240
6767
|
}
|
|
5241
6768
|
|
|
5242
6769
|
// \u2500\u2500 Selector helper \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
@@ -5457,6 +6984,100 @@ function repositionDragSibling(dragEl, clientY) {
|
|
|
5457
6984
|
}
|
|
5458
6985
|
}
|
|
5459
6986
|
|
|
6987
|
+
function isMoveSwapSkippableSibling(el) {
|
|
6988
|
+
if (!el || el.nodeType !== 1) return true;
|
|
6989
|
+
if (isDomTreeSkippableTagName(el.tagName)) return true;
|
|
6990
|
+
try {
|
|
6991
|
+
if (el.hasAttribute && el.hasAttribute('hidden')) return true;
|
|
6992
|
+
if (el.getAttribute && el.getAttribute('data-vve-hidden') === '1') return true;
|
|
6993
|
+
} catch(_) {}
|
|
6994
|
+
try {
|
|
6995
|
+
if (el.style && el.style.display === 'none') return true;
|
|
6996
|
+
if (el.style && el.style.visibility === 'hidden') return true;
|
|
6997
|
+
} catch(_) {}
|
|
6998
|
+
try {
|
|
6999
|
+
var view = el.ownerDocument && el.ownerDocument.defaultView;
|
|
7000
|
+
var cs = view && view.getComputedStyle ? view.getComputedStyle(el) : null;
|
|
7001
|
+
if (cs && (cs.display === 'none' || cs.visibility === 'hidden')) return true;
|
|
7002
|
+
} catch(_) {}
|
|
7003
|
+
return false;
|
|
7004
|
+
}
|
|
7005
|
+
|
|
7006
|
+
function findMoveSwapSibling(el, direction) {
|
|
7007
|
+
if (!el) return null;
|
|
7008
|
+
var node = direction < 0 ? el.previousElementSibling : el.nextElementSibling;
|
|
7009
|
+
while (node && isMoveSwapSkippableSibling(node)) {
|
|
7010
|
+
node = direction < 0 ? node.previousElementSibling : node.nextElementSibling;
|
|
7011
|
+
}
|
|
7012
|
+
return node;
|
|
7013
|
+
}
|
|
7014
|
+
|
|
7015
|
+
function isMoveParentEscapeBlocked(parent) {
|
|
7016
|
+
if (!parent || parent.nodeType !== 1) return true;
|
|
7017
|
+
var tag = (parent.tagName || '').toLowerCase();
|
|
7018
|
+
if (tag === 'html' || tag === 'body') return true;
|
|
7019
|
+
try {
|
|
7020
|
+
var doc = parent.ownerDocument;
|
|
7021
|
+
if (doc && (parent === doc.documentElement || parent === doc.body)) return true;
|
|
7022
|
+
} catch(_) {}
|
|
7023
|
+
return false;
|
|
7024
|
+
}
|
|
7025
|
+
|
|
7026
|
+
/** When no visual sibling exists, lift the node to the grandparent (before/after its parent). */
|
|
7027
|
+
function canMoveEscapeToParent(el, direction) {
|
|
7028
|
+
if (!el || !el.parentElement) return false;
|
|
7029
|
+
var parent = el.parentElement;
|
|
7030
|
+
if (isMoveParentEscapeBlocked(parent) || !parent.parentElement) return false;
|
|
7031
|
+
if (findMoveSwapSibling(el, direction)) return false;
|
|
7032
|
+
return true;
|
|
7033
|
+
}
|
|
7034
|
+
|
|
7035
|
+
function canMoveElDirection(el, direction) {
|
|
7036
|
+
if (!el || !el.parentElement) return false;
|
|
7037
|
+
return !!findMoveSwapSibling(el, direction) || canMoveEscapeToParent(el, direction);
|
|
7038
|
+
}
|
|
7039
|
+
|
|
7040
|
+
function moveElByDirection(el, direction) {
|
|
7041
|
+
if (!el || !el.parentElement) return false;
|
|
7042
|
+
var parent = el.parentElement;
|
|
7043
|
+
var sibling = findMoveSwapSibling(el, direction);
|
|
7044
|
+
if (sibling) {
|
|
7045
|
+
if (direction < 0) parent.insertBefore(el, sibling);
|
|
7046
|
+
else parent.insertBefore(sibling, el);
|
|
7047
|
+
return true;
|
|
7048
|
+
}
|
|
7049
|
+
if (!canMoveEscapeToParent(el, direction)) return false;
|
|
7050
|
+
var grandparent = parent.parentElement;
|
|
7051
|
+
if (!grandparent) return false;
|
|
7052
|
+
if (direction < 0) grandparent.insertBefore(el, parent);
|
|
7053
|
+
else grandparent.insertBefore(el, parent.nextSibling);
|
|
7054
|
+
return true;
|
|
7055
|
+
}
|
|
7056
|
+
|
|
7057
|
+
function syncMoveFloaterButtons(el) {
|
|
7058
|
+
var upBtn = document.getElementById('sf-move-up');
|
|
7059
|
+
var downBtn = document.getElementById('sf-move-down');
|
|
7060
|
+
if (!upBtn || !downBtn) return;
|
|
7061
|
+
var canUp = canMoveElDirection(el, -1);
|
|
7062
|
+
var canDown = canMoveElDirection(el, 1);
|
|
7063
|
+
upBtn.disabled = !canUp;
|
|
7064
|
+
downBtn.disabled = !canDown;
|
|
7065
|
+
if (canUp) {
|
|
7066
|
+
upBtn.title = findMoveSwapSibling(el, -1)
|
|
7067
|
+
? 'Move up'
|
|
7068
|
+
: 'Move up (out of container)';
|
|
7069
|
+
} else {
|
|
7070
|
+
upBtn.title = 'Cannot move up';
|
|
7071
|
+
}
|
|
7072
|
+
if (canDown) {
|
|
7073
|
+
downBtn.title = findMoveSwapSibling(el, 1)
|
|
7074
|
+
? 'Move down'
|
|
7075
|
+
: 'Move down (out of container)';
|
|
7076
|
+
} else {
|
|
7077
|
+
downBtn.title = 'Cannot move down';
|
|
7078
|
+
}
|
|
7079
|
+
}
|
|
7080
|
+
|
|
5460
7081
|
function recordReorderAfterDrag(movedEl) {
|
|
5461
7082
|
if (!activeVarId || !movedEl || !movedEl.parentElement) return;
|
|
5462
7083
|
var prev = movedEl.previousElementSibling;
|
|
@@ -5485,13 +7106,11 @@ function recordReorderAfterDrag(movedEl) {
|
|
|
5485
7106
|
}
|
|
5486
7107
|
|
|
5487
7108
|
function moveSelectedElByDirection(direction) {
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
if (!
|
|
5492
|
-
|
|
5493
|
-
else p.insertBefore(sibling, selectedEl);
|
|
5494
|
-
recordReorderAfterDrag(selectedEl);
|
|
7109
|
+
var el = recoverSelectedElement(false) || selectedEl;
|
|
7110
|
+
if (!el || !el.parentElement) return;
|
|
7111
|
+
selectedEl = el;
|
|
7112
|
+
if (!moveElByDirection(el, direction)) return;
|
|
7113
|
+
recordReorderAfterDrag(el);
|
|
5495
7114
|
saveCurrentVariationHtml();
|
|
5496
7115
|
recomputeEditorDirty();
|
|
5497
7116
|
scheduleDomTreeRefresh();
|
|
@@ -5591,6 +7210,7 @@ function attachClickHandler() {
|
|
|
5591
7210
|
deselectElement(); return;
|
|
5592
7211
|
}
|
|
5593
7212
|
selectElement(target);
|
|
7213
|
+
if (currentMainTab !== 'design') switchMainTab('design');
|
|
5594
7214
|
}, true);
|
|
5595
7215
|
} catch(_) {}
|
|
5596
7216
|
}
|
|
@@ -5695,15 +7315,18 @@ function syncIframeInteractions(reason) {
|
|
|
5695
7315
|
// \u2500\u2500 HTML insertion (Components / Sections) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
5696
7316
|
/** Full snippets for Vvveb keys whose html field is placeholder text, not markup. */
|
|
5697
7317
|
var VVVEB_INSERT_HTML_OVERRIDES = {
|
|
5698
|
-
'html/gridrow': '<div
|
|
5699
|
-
'html/gridcolumn': '<div
|
|
5700
|
-
'html/container': '<div
|
|
5701
|
-
'html/btn-link': '<a
|
|
5702
|
-
'html/btn': '<button type="button"
|
|
5703
|
-
'html/
|
|
5704
|
-
'html/
|
|
5705
|
-
'html/
|
|
5706
|
-
'html/
|
|
7318
|
+
'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>',
|
|
7319
|
+
'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>',
|
|
7320
|
+
'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>',
|
|
7321
|
+
'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>',
|
|
7322
|
+
'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>',
|
|
7323
|
+
'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>',
|
|
7324
|
+
'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>',
|
|
7325
|
+
'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>',
|
|
7326
|
+
'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>',
|
|
7327
|
+
'html/breadcrumbitem': '<li style="display:inline;font-size:14px;color:#64748b"><a href="#" style="color:#2563eb;text-decoration:none">Item</a></li>',
|
|
7328
|
+
'html/listitem': '<li style="padding:10px 14px;font-size:14px;color:#334155;border:1px solid #e2e8f0;border-radius:6px;background:#fff">List item</li>',
|
|
7329
|
+
'html/tablebody': '<tbody><tr><td style="padding:10px 12px;border:1px solid #e2e8f0;font-size:14px">Cell</td></tr></tbody>',
|
|
5707
7330
|
};
|
|
5708
7331
|
|
|
5709
7332
|
function buildHtmlFromVvvebComponent(comp, typeKey) {
|
|
@@ -5731,7 +7354,7 @@ function insertVvvebComponent(typeKey) {
|
|
|
5731
7354
|
insertHtml(html);
|
|
5732
7355
|
}
|
|
5733
7356
|
|
|
5734
|
-
function insertHtml(html) {
|
|
7357
|
+
function insertHtml(html, options) {
|
|
5735
7358
|
if (!html) return;
|
|
5736
7359
|
try {
|
|
5737
7360
|
var iframe = document.getElementById('iframeId');
|
|
@@ -5759,7 +7382,18 @@ function insertHtml(html) {
|
|
|
5759
7382
|
} else {
|
|
5760
7383
|
doc.body.appendChild(frag);
|
|
5761
7384
|
}
|
|
5762
|
-
if (firstEl)
|
|
7385
|
+
if (firstEl) {
|
|
7386
|
+
try {
|
|
7387
|
+
firstEl.setAttribute('data-vve-instance', generateVveInstanceId());
|
|
7388
|
+
} catch(_) {}
|
|
7389
|
+
htmlStr = firstEl.outerHTML;
|
|
7390
|
+
}
|
|
7391
|
+
if (firstEl) {
|
|
7392
|
+
if (currentMainTab !== 'design') switchMainTab('design');
|
|
7393
|
+
selectElement(firstEl, {
|
|
7394
|
+
preferredAccSection: options && options.defaultAccSection,
|
|
7395
|
+
});
|
|
7396
|
+
}
|
|
5763
7397
|
if (activeVarId) {
|
|
5764
7398
|
var insertRow = {
|
|
5765
7399
|
selector: anchorSel,
|
|
@@ -5791,7 +7425,7 @@ function renderSidebar(filter) {
|
|
|
5791
7425
|
baseFiltered.forEach(function(c) {
|
|
5792
7426
|
var item = document.createElement('div'); item.className = 'cg-item'; item.title = 'Insert ' + c.name;
|
|
5793
7427
|
item.innerHTML = '<div class="cg-icon"><i class="bi ' + c.icon + '"></i></div><div class="cg-name">' + c.name + '</div>';
|
|
5794
|
-
item.onclick = function() { insertHtml(c.html); };
|
|
7428
|
+
item.onclick = function() { insertHtml(c.html, { defaultAccSection: c.defaultAccSection }); };
|
|
5795
7429
|
g1.appendChild(item);
|
|
5796
7430
|
});
|
|
5797
7431
|
compTab.appendChild(g1);
|
|
@@ -5831,8 +7465,10 @@ function renderSidebar(filter) {
|
|
|
5831
7465
|
var ch = document.createElement('div'); ch.className = 'cg-hdr'; ch.textContent = 'CRO Components'; secTab.appendChild(ch);
|
|
5832
7466
|
croFiltered.forEach(function(sec) {
|
|
5833
7467
|
var item = document.createElement('div'); item.className = 'sec-item';
|
|
5834
|
-
item.innerHTML = '<div class="sec-thumb">'+(sec
|
|
5835
|
-
item.onclick = function() {
|
|
7468
|
+
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>';
|
|
7469
|
+
item.onclick = function() {
|
|
7470
|
+
insertHtml(sec.html, { defaultAccSection: sec.defaultAccSection || 'content' });
|
|
7471
|
+
};
|
|
5836
7472
|
secTab.appendChild(item);
|
|
5837
7473
|
});
|
|
5838
7474
|
}
|
|
@@ -5845,7 +7481,9 @@ function renderSidebar(filter) {
|
|
|
5845
7481
|
if (!hasVv) { hasVv = true; var sh = document.createElement('div'); sh.className = 'cg-hdr'; sh.textContent = 'Bootstrap Sections'; secTab.appendChild(sh); }
|
|
5846
7482
|
var sel = document.createElement('div'); sel.className = 'sec-item';
|
|
5847
7483
|
sel.innerHTML = '<div class="sec-thumb">\u{1F4D0}</div><div class="sec-info"><div class="sec-name">'+snm+'</div></div>';
|
|
5848
|
-
sel.onclick = (function(s){ return function(){
|
|
7484
|
+
sel.onclick = (function(s){ return function(){
|
|
7485
|
+
insertHtml(s.html || '', { defaultAccSection: 'content' });
|
|
7486
|
+
}; })(sec);
|
|
5849
7487
|
secTab.appendChild(sel);
|
|
5850
7488
|
}
|
|
5851
7489
|
}
|
|
@@ -5861,11 +7499,7 @@ document.getElementById('comp-search').addEventListener('input', function() {
|
|
|
5861
7499
|
});
|
|
5862
7500
|
var btnAddElement = document.getElementById('btn-add-element');
|
|
5863
7501
|
if (btnAddElement) {
|
|
5864
|
-
btnAddElement.addEventListener('click',
|
|
5865
|
-
e.preventDefault();
|
|
5866
|
-
e.stopPropagation();
|
|
5867
|
-
toggleSectionComponentsPanel();
|
|
5868
|
-
});
|
|
7502
|
+
btnAddElement.addEventListener('click', handleAddElementClick);
|
|
5869
7503
|
}
|
|
5870
7504
|
|
|
5871
7505
|
// \u2500\u2500 Save / Close \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
@@ -6070,13 +7704,19 @@ function bindLoadingTooltipPositioning() {
|
|
|
6070
7704
|
// \u2500\u2500 Init \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
6071
7705
|
function registerCROSections() {
|
|
6072
7706
|
if (typeof Vvveb === 'undefined' || !Vvveb.Sections) return;
|
|
6073
|
-
CRO_SECTIONS.forEach(function(sec) {
|
|
7707
|
+
CRO_SECTIONS.forEach(function(sec) {
|
|
7708
|
+
Vvveb.Sections.add(sec.key, {
|
|
7709
|
+
name: sec.name,
|
|
7710
|
+
image: sec.image ? (CRO_SECTION_IMAGE_ROUTE + sec.image) : '',
|
|
7711
|
+
html: sec.html,
|
|
7712
|
+
});
|
|
7713
|
+
});
|
|
6074
7714
|
}
|
|
6075
7715
|
|
|
6076
7716
|
window.addEventListener('load', function() {
|
|
6077
7717
|
registerCROSections();
|
|
6078
7718
|
bindViewportControls();
|
|
6079
|
-
switchSectionComponentsTab(currentSectionComponentsTab);
|
|
7719
|
+
// switchSectionComponentsTab(currentSectionComponentsTab);
|
|
6080
7720
|
renderElementsTree(document.getElementById('comp-search').value);
|
|
6081
7721
|
vvvebReady = true;
|
|
6082
7722
|
bindLoadingTooltipPositioning();
|
|
@@ -6149,6 +7789,10 @@ window.addEventListener('load', function() {
|
|
|
6149
7789
|
syncIframeInteractions('iframe-load');
|
|
6150
7790
|
});
|
|
6151
7791
|
|
|
7792
|
+
var sfAdd = document.getElementById('sf-add');
|
|
7793
|
+
if (sfAdd) {
|
|
7794
|
+
sfAdd.addEventListener('click', handleAddElementClick);
|
|
7795
|
+
}
|
|
6152
7796
|
var sfMoveUp = document.getElementById('sf-move-up');
|
|
6153
7797
|
if (sfMoveUp) {
|
|
6154
7798
|
sfMoveUp.addEventListener('click', function(e) {
|
|
@@ -6248,6 +7892,20 @@ function createVisualEditorMiddleware(options) {
|
|
|
6248
7892
|
res.end(buildVvvebEditorHtml());
|
|
6249
7893
|
return;
|
|
6250
7894
|
}
|
|
7895
|
+
if (pathname.startsWith(CRO_SECTION_IMAGE_ROUTE)) {
|
|
7896
|
+
const filename = pathname.slice(CRO_SECTION_IMAGE_ROUTE.length);
|
|
7897
|
+
const filePath = resolveCroSectionImagePath(filename);
|
|
7898
|
+
if (!filePath) {
|
|
7899
|
+
res.statusCode = 404;
|
|
7900
|
+
res.end("Not found");
|
|
7901
|
+
return;
|
|
7902
|
+
}
|
|
7903
|
+
res.setHeader("Content-Type", "image/png");
|
|
7904
|
+
res.setHeader("Cache-Control", "public, max-age=86400");
|
|
7905
|
+
setFrameHeaders(req, res);
|
|
7906
|
+
res.end(fs.readFileSync(filePath));
|
|
7907
|
+
return;
|
|
7908
|
+
}
|
|
6251
7909
|
if (pathname === "/api/generate-test" && enableGenerateTestApi) {
|
|
6252
7910
|
if (req.method === "OPTIONS") {
|
|
6253
7911
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
@@ -6386,7 +8044,6 @@ function createVisualEditorMiddleware(options) {
|
|
|
6386
8044
|
const trackingMarkersForRequest = mergeTrackingMarkers(
|
|
6387
8045
|
extraTrackingMarkersForRequest
|
|
6388
8046
|
);
|
|
6389
|
-
console.log("trackingMarkersForRequest", trackingMarkersForRequest);
|
|
6390
8047
|
const strictFreezeParam = (url.searchParams.get("strictObserverFreeze") || "").toLowerCase();
|
|
6391
8048
|
const strictObserverFreezeForRequest = strictFreezeParam === "1" || strictFreezeParam === "true" || strictFreezeParam === "yes" ? true : strictFreezeParam === "0" || strictFreezeParam === "false" || strictFreezeParam === "no" ? false : strictObserverFreeze;
|
|
6392
8049
|
if (!targetUrl) {
|
|
@@ -7087,6 +8744,13 @@ function visualEditorProxyPlugin(options) {
|
|
|
7087
8744
|
generateBundle() {
|
|
7088
8745
|
this.emitFile({ type: "asset", fileName: "bridge.js", source: BRIDGE_SCRIPT });
|
|
7089
8746
|
this.emitFile({ type: "asset", fileName: "vvveb-editor/index.html", source: buildVvvebEditorHtml() });
|
|
8747
|
+
for (const imagePath of listCroSectionImageFiles()) {
|
|
8748
|
+
this.emitFile({
|
|
8749
|
+
type: "asset",
|
|
8750
|
+
fileName: path.join("images", "cro-sections", path.basename(imagePath)),
|
|
8751
|
+
source: fs.readFileSync(imagePath)
|
|
8752
|
+
});
|
|
8753
|
+
}
|
|
7090
8754
|
},
|
|
7091
8755
|
configureServer(server) {
|
|
7092
8756
|
server.middlewares.use(mw);
|