|
|
|
|
@@ -24,7 +24,7 @@
|
|
|
|
|
.btn.secondary{background:transparent;color:var(--text);border:1px solid var(--border)}
|
|
|
|
|
.btn.icon{width:34px;height:34px;padding:0;display:flex;align-items:center;justify-content:center}
|
|
|
|
|
.btn.active{border-color:var(--accent);box-shadow:0 0 0 2px rgba(89,217,200,.15)}
|
|
|
|
|
.preview-shell{background:#0f1520;border:1px solid #222b3a;border-radius:18px;padding:14px;width:100%;max-width:1200px;margin:0 auto}
|
|
|
|
|
.preview-shell{background:#0f1520;border:1px solid #222b3a;border-radius:18px;padding:14px;width:100%;max-width:none;margin:0 auto}
|
|
|
|
|
body.ub24 .preview-shell{background:#eef1f6;border-color:#e5e7eb}
|
|
|
|
|
body.ub24 .apple-bar{display:none}
|
|
|
|
|
body.ub24 .preview-shell{padding:0;border-radius:12px}
|
|
|
|
|
@@ -259,7 +259,6 @@
|
|
|
|
|
<div class="apple">
|
|
|
|
|
<div class="apple-bar">
|
|
|
|
|
<span class="apple-dot red"></span><span class="apple-dot yellow"></span><span class="apple-dot green"></span>
|
|
|
|
|
<span style="margin-left:6px">{{ slug }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="canvas" id="previewCanvas"></div>
|
|
|
|
|
</div>
|
|
|
|
|
@@ -469,7 +468,7 @@ const state = {
|
|
|
|
|
case "map": return { title:"Ubicacion", address:"" };
|
|
|
|
|
case "button": return { text:"Accion", url:"#", style:"primary", size:"md"};
|
|
|
|
|
case "social": return { instagram:"", facebook:"", whatsapp:"", tiktok:"", youtube:"", icon_size:18, icon_color:"#0b0c10", show_text:true, icon_style:"pill" };
|
|
|
|
|
case "video": return { url:"" };
|
|
|
|
|
case "video": return { url:"", description:"" };
|
|
|
|
|
case "review": return { title:"Reseña destacada", name:"Cliente feliz", text:"Excelente servicio y resultados profesionales.", rating:5, style:"card" };
|
|
|
|
|
case "calendar": return { title:"Agenda una cita", note:"Disponible en plan premium. Proximamente.", embed_url:"" };
|
|
|
|
|
default: return {};
|
|
|
|
|
@@ -672,11 +671,11 @@ const state = {
|
|
|
|
|
const logo = state.settings.logo_url ? `<img src="${escapeHtml(state.settings.logo_url)}" alt="Logo" />` : "";
|
|
|
|
|
return `<div class="site-nav">
|
|
|
|
|
<div class="site-brand">${logo}<span>${escapeHtml(state.settings.site_name||"GKACHELE")}</span></div>
|
|
|
|
|
<div class="menu-inline site-nav-links">${links || '<span class="menu-empty">Sin secciones</span>'}</div>
|
|
|
|
|
<div class="menu-inline site-nav-links">${links}</div>
|
|
|
|
|
<a href="#contacto" class="site-nav-cta">Contactar</a>
|
|
|
|
|
<details class="menu-accordion">
|
|
|
|
|
<summary>Menu</summary>
|
|
|
|
|
<div class="menu-links">${mobileLinks || '<span class="menu-empty">Sin secciones</span>'}</div>
|
|
|
|
|
<div class="menu-links">${mobileLinks}</div>
|
|
|
|
|
</details>
|
|
|
|
|
</div>`;
|
|
|
|
|
}
|
|
|
|
|
@@ -819,11 +818,12 @@ const state = {
|
|
|
|
|
}
|
|
|
|
|
if (block.type==="video"){
|
|
|
|
|
const embed = normalizeVideoUrl(block.data.url);
|
|
|
|
|
const desc = block.data.description ? `<div style="margin-top:8px;color:var(--site-muted);font-size:12px">${escapeHtml(block.data.description)}</div>` : "";
|
|
|
|
|
if (embed){
|
|
|
|
|
if (embed.startsWith("data:video/")){
|
|
|
|
|
return `<video src="${escapeHtml(embed)}" style="width:100%;border-radius:12px" controls></video>`;
|
|
|
|
|
return `<video src="${escapeHtml(embed)}" style="width:100%;border-radius:12px" controls></video>${desc}`;
|
|
|
|
|
}
|
|
|
|
|
return `<div style="position:relative;padding-top:56.25%;border-radius:12px;overflow:hidden"><iframe src="${escapeHtml(embed)}" style="position:absolute;inset:0;width:100%;height:100%;border:0" allowfullscreen></iframe></div>`;
|
|
|
|
|
return `<div style="position:relative;padding-top:56.25%;border-radius:12px;overflow:hidden"><iframe src="${escapeHtml(embed)}" style="position:absolute;inset:0;width:100%;height:100%;border:0" allowfullscreen></iframe></div>${desc}`;
|
|
|
|
|
}
|
|
|
|
|
return `<div class="inline-drop" data-inline-video="true">Suelta video o click</div>`;
|
|
|
|
|
}
|
|
|
|
|
@@ -944,7 +944,7 @@ const state = {
|
|
|
|
|
el.style.transform = `translate3d(${pos.x}px, ${pos.y}px, 0)`;
|
|
|
|
|
const defaultWidth = block.type === "menu" ? 90 : (state.settings.two_col ? 48 : 70);
|
|
|
|
|
const w = Math.max(30, Math.min(100, Number(block.data?.width || defaultWidth)));
|
|
|
|
|
el.style.width = `calc(${w}% - 8px)`;
|
|
|
|
|
el.style.width = `${w}%`;
|
|
|
|
|
const h = Number(block.data?.height || 0);
|
|
|
|
|
if (h > 60){ el.style.height = h + "px"; }
|
|
|
|
|
el.style.cursor = "grab";
|
|
|
|
|
@@ -1018,12 +1018,13 @@ const state = {
|
|
|
|
|
});
|
|
|
|
|
if (state.settings.free_drag){
|
|
|
|
|
let maxBottom = 700;
|
|
|
|
|
state.blocks.forEach((b)=>{
|
|
|
|
|
const h = Number(b.data?.height || 220);
|
|
|
|
|
const y = Number(b.pos?.y || 0);
|
|
|
|
|
maxBottom = Math.max(maxBottom, y + h + 120);
|
|
|
|
|
inner.querySelectorAll(".block").forEach((node)=>{
|
|
|
|
|
const n = node;
|
|
|
|
|
maxBottom = Math.max(maxBottom, n.offsetTop + n.offsetHeight + 120);
|
|
|
|
|
});
|
|
|
|
|
canvas.style.minHeight = maxBottom + "px";
|
|
|
|
|
} else {
|
|
|
|
|
canvas.style.minHeight = "700px";
|
|
|
|
|
}
|
|
|
|
|
const scrollBtn = document.createElement("button");
|
|
|
|
|
scrollBtn.className = "scroll-btn";
|
|
|
|
|
@@ -1082,6 +1083,8 @@ const state = {
|
|
|
|
|
let html = `<div style="font-weight:600;margin-bottom:6px;text-transform:capitalize">${block.type}</div>`;
|
|
|
|
|
const data=block.data||{};
|
|
|
|
|
const input=(label,id,val)=>`<div class="row"><label>${label}</label><input id="${id}" type="text" value="${escapeHtml(val||"")}"></div>`;
|
|
|
|
|
const widthVal = Math.max(30, Math.min(100, Number(data.width || 100)));
|
|
|
|
|
html += `<div class="row"><label>Ancho bloque (%)</label><input id="blockWidth" type="range" min="30" max="100" value="${widthVal}"><div id="blockWidthValue" style="margin-top:4px;color:var(--muted);font-size:12px">${widthVal}%</div></div>`;
|
|
|
|
|
if (block.type==="menu"){
|
|
|
|
|
html+=input("Titulo","menuTitle",data.title);
|
|
|
|
|
} else if (block.type==="hero"){
|
|
|
|
|
@@ -1142,6 +1145,7 @@ const state = {
|
|
|
|
|
html+=`<div class="row"><label>Mostrar texto</label><input id="socialShowText" type="checkbox" ${data.show_text !== false ? "checked" : ""}></div>`;
|
|
|
|
|
} else if (block.type==="video"){
|
|
|
|
|
html+=input("URL video","videoUrl",data.url);
|
|
|
|
|
html+=input("Descripcion","videoDesc",data.description);
|
|
|
|
|
html+=`<div class="row"><label>Video (arrastrar)</label><div class="dropzone" id="videoDrop">${data.url ? "Video cargado" : "Suelta video o click"}</div><input id="videoFile" type="file" accept="video/*" hidden></div>`;
|
|
|
|
|
} else if (block.type==="map"){
|
|
|
|
|
html+=input("Titulo","mapTitle",data.title);
|
|
|
|
|
@@ -1188,10 +1192,21 @@ const state = {
|
|
|
|
|
el.addEventListener("input",()=>applyInspector(block));
|
|
|
|
|
el.addEventListener("change",()=>applyInspector(block));
|
|
|
|
|
});
|
|
|
|
|
const widthEl = document.getElementById("blockWidth");
|
|
|
|
|
const widthValueEl = document.getElementById("blockWidthValue");
|
|
|
|
|
if (widthEl && widthValueEl){
|
|
|
|
|
const updateWidthLabel = ()=>{ widthValueEl.textContent = `${widthEl.value}%`; };
|
|
|
|
|
widthEl.addEventListener("input", updateWidthLabel);
|
|
|
|
|
updateWidthLabel();
|
|
|
|
|
}
|
|
|
|
|
document.getElementById("deleteBlockBtn").addEventListener("click",()=>{ state.blocks=state.blocks.filter(b=>b.id!==block.id); selectedBlockId=null; renderInspector(); renderPreview(); });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function applyInspector(block){
|
|
|
|
|
const widthEl = document.getElementById("blockWidth");
|
|
|
|
|
if (widthEl){
|
|
|
|
|
block.data.width = Math.max(30, Math.min(100, Number(widthEl.value || 100)));
|
|
|
|
|
}
|
|
|
|
|
if (block.type==="menu"){ block.data.title=document.getElementById("menuTitle").value; }
|
|
|
|
|
else if (block.type==="hero"){
|
|
|
|
|
block.data.title=document.getElementById("heroTitle").value;
|
|
|
|
|
@@ -1241,7 +1256,11 @@ const state = {
|
|
|
|
|
const showEl = document.getElementById("socialShowText");
|
|
|
|
|
if (showEl){ block.data.show_text = !!showEl.checked; }
|
|
|
|
|
}
|
|
|
|
|
else if (block.type==="video"){ block.data.url=document.getElementById("videoUrl").value; }
|
|
|
|
|
else if (block.type==="video"){
|
|
|
|
|
block.data.url=document.getElementById("videoUrl").value;
|
|
|
|
|
const vd = document.getElementById("videoDesc");
|
|
|
|
|
if (vd){ block.data.description = vd.value; }
|
|
|
|
|
}
|
|
|
|
|
else if (block.type==="map"){
|
|
|
|
|
block.data.title=document.getElementById("mapTitle").value;
|
|
|
|
|
block.data.address=document.getElementById("mapAddress").value;
|
|
|
|
|
@@ -1578,7 +1597,7 @@ const state = {
|
|
|
|
|
};
|
|
|
|
|
document.getElementById("btnSizePhone").addEventListener("click",()=>setSize("520px","btnSizePhone"));
|
|
|
|
|
document.getElementById("btnSizeTablet").addEventListener("click",()=>setSize("820px","btnSizeTablet"));
|
|
|
|
|
document.getElementById("btnSizeDesktop").addEventListener("click",()=>setSize("1200px","btnSizeDesktop"));
|
|
|
|
|
document.getElementById("btnSizeDesktop").addEventListener("click",()=>setSize("100%","btnSizeDesktop"));
|
|
|
|
|
setShellClass("size-desktop");
|
|
|
|
|
}
|
|
|
|
|
function wireThemeToggle(){
|
|
|
|
|
@@ -1648,27 +1667,21 @@ const state = {
|
|
|
|
|
const previewBtn = document.getElementById("btnPreview");
|
|
|
|
|
if (previewBtn){
|
|
|
|
|
previewBtn.addEventListener("click",()=>{
|
|
|
|
|
if (BUILDER_MODE === "ub24"){
|
|
|
|
|
document.body.classList.toggle("preview-mode");
|
|
|
|
|
const app = document.querySelector(".app");
|
|
|
|
|
const isPreview = document.body.classList.contains("preview-mode");
|
|
|
|
|
if (app) app.style.display = isPreview ? "none" : "grid";
|
|
|
|
|
const shell = document.querySelector(".preview-shell");
|
|
|
|
|
if (shell){
|
|
|
|
|
if (isPreview){
|
|
|
|
|
shell.style.maxWidth = "1200px";
|
|
|
|
|
shell.style.margin = "40px auto";
|
|
|
|
|
shell.style.display = "block";
|
|
|
|
|
document.body.appendChild(shell);
|
|
|
|
|
} else {
|
|
|
|
|
const main = document.querySelector(".main");
|
|
|
|
|
if (main) main.appendChild(shell);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
document.body.classList.toggle("preview-mode");
|
|
|
|
|
const isPreview = document.body.classList.contains("preview-mode");
|
|
|
|
|
const sidebar = document.querySelector(".sidebar");
|
|
|
|
|
const inspector = document.querySelector(".inspector");
|
|
|
|
|
const main = document.querySelector(".main");
|
|
|
|
|
if (sidebar) sidebar.style.display = isPreview ? "none" : "";
|
|
|
|
|
if (inspector) inspector.style.display = isPreview ? "none" : "";
|
|
|
|
|
if (main) main.style.padding = isPreview ? "8px" : "";
|
|
|
|
|
const shell = document.querySelector(".preview-shell");
|
|
|
|
|
if (shell){
|
|
|
|
|
shell.style.maxWidth = isPreview ? "100%" : "";
|
|
|
|
|
shell.style.margin = isPreview ? "8px auto" : "";
|
|
|
|
|
}
|
|
|
|
|
if (!SITE_SLUG){ alert("No hay slug"); return; }
|
|
|
|
|
window.open("/" + SITE_SLUG, "_blank");
|
|
|
|
|
window.scrollTo({ top: 0, behavior: "smooth" });
|
|
|
|
|
return;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
const pageSelect = document.getElementById("pageSelect");
|
|
|
|
|
|