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