Lo más Solicitados en Cortinas
Professional persiana y toldo flexalum in San Borja
Find a persiana y toldo flexalum in San Borja. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam varius nec ex fermentum vehicula. Cras sodales est nec gravida pretium. Integer libero arcu, pulvinar vitae tempus eget, convallis ut nulla.
Meet our persianas y toldos flexalum at our salon
Our persianas y toldos flexalum are the best persiana y toldo flexalum in San Borja. Meet our team now!
Get a haircut from one of our persianas y toldos flexalum in San Borja
Donec ac tortor vitae purus cursus tempor. Duis non hendrerit augue, ut consectetur erat. Suspendisse persiana y toldo flexalum, magna at lobortis pharetra, massa orci lacinia massa, non tempus turpis nisl nec libero. Sed sed enim lorem. Cras et orci sapien.
Book now
Wide variety of persiana y toldo flexalum services in San Borja
Suspendisse fermentum lacus vitae tristique consectetur. Nunc luctus volutpat arcu, eu tempor odio pulvinar in. Sed urna nulla, finibus ut lorem San Borja, consectetur finibus orci.
- Hair coloring in San Borja
- Eyebrow styling in San Borja
- Washing hair in San Borja
Book a persiana y toldo flexalum in San Borja
Nulla sagittis urna ultrices tortor viverra hendrerit. Phasellus sit amet luctus mauris, eu finibus mauris. Sed blandit nulla in diam porta, ac viverra arcu pretium. Nulla facilisi. Suspendisse ut nisl consequat, maximus enim ut, congue augue. Vivamus eget vehicula augue. Aenean eget ligula sed lacus mollis congue.
Book now
Las 6 cortinas de moda en 2026 para Lima
' +
'
' + item.title + '
' +
'
' + item.desc + '
' +
'
' + item.cta + ' →' +
'
';
return a;
}
/* ════════════════════════════
Init
════════════════════════════ */
function init () {
var grid = document.getElementById('nvlxTGrid');
var slider = document.getElementById('nvlxTSlider');
var track = document.getElementById('nvlxTTrack');
var dotsEl = document.getElementById('nvlxTDots');
if (!grid || !track) return;
if (grid.dataset.nvlxInit === '1') return; /* evitar doble init en editor Elementor */
grid.dataset.nvlxInit = '1';
var N = ITEMS.length;
var cur = 0;
var busy = false;
var autoTm = null;
var dragX = 0;
var isDrag = false;
var tX = 0;
/* ── Poblar GRILLA desktop ── */
ITEMS.forEach(function (item) { grid.appendChild(makeCard(item)); });
/* ── Poblar TRACK del slider: reales + clones ── */
ITEMS.forEach(function (item) { track.appendChild(makeCard(item)); });
for (var r = 0; r < CFG.clones; r++) {
ITEMS.forEach(function (item) { track.appendChild(makeCard(item)); });
}
/* ── Dots ── */
for (var i = 0; i < N; i++) {
var d = document.createElement('button');
d.className = 'nvlx-t-dot' + (i === 0 ? ' nvlx-on' : '');
d.setAttribute('aria-label', 'Ver tendencia ' + (i + 1));
d.dataset.idx = i;
d.addEventListener('click', function () {
jumpTo(+this.dataset.idx);
resetAuto();
});
dotsEl.appendChild(d);
}
/* ── Medidas ── */
function cw () { var c = track.querySelector('.nvlx-t-card'); return c ? c.offsetWidth : 285; }
function gap () { return window.innerWidth <= 480 ? 14 : 18; }
function step () { return cw() + gap(); }
function off (i) { return i * step(); }
/* ── Aplicar posición ── */
function applyPos (px, animate) {
track.style.transition = animate
? 'transform ' + CFG.animMs + 'ms ' + CFG.easing
: 'none';
track.style.transform = 'translateX(-' + px + 'px)';
}
/* ── Actualizar dots y opacidad de cards ── */
function updateUI () {
/* dots */
var ds = dotsEl.querySelectorAll('.nvlx-t-dot');
ds.forEach(function (d, i) { d.classList.toggle('nvlx-on', i === cur); });
/* opacidad sutil en cards del slider */
var cs = track.querySelectorAll('.nvlx-t-card');
cs.forEach(function (c, i) { c.style.opacity = (i === cur) ? '1' : '0.85'; });
}
/* ── jumpTo: ir directo sin animación (dots, resize) ── */
function jumpTo (idx) {
cur = ((idx % N) + N) % N;
applyPos(off(cur), false);
updateUI();
}
/* ── advance: siguiente card con loop infinito ── */
function advance () {
if (busy) return;
busy = true;
if (cur < N - 1) {
cur++;
applyPos(off(cur), true);
updateUI();
setTimeout(function () { busy = false; }, CFG.animMs + 40);
} else {
/* Último real → anima hacia clon[0] en posición N, luego salta invisible a 0 */
applyPos(off(N), true);
cur = 0;
updateUI();
setTimeout(function () {
applyPos(off(0), false);
busy = false;
}, CFG.animMs + 40);
}
}
/* ── retreat: card anterior con loop ── */
function retreat () {
if (busy) return;
busy = true;
if (cur > 0) {
cur--;
applyPos(off(cur), true);
updateUI();
setTimeout(function () { busy = false; }, CFG.animMs + 40);
} else {
/* Primero → salta instantáneo al clon del último, luego anima hacia atrás */
applyPos(off(N + N - 1), false);
track.getBoundingClientRect(); /* forzar reflow */
cur = N - 1;
applyPos(off(cur), true);
updateUI();
setTimeout(function () { busy = false; }, CFG.animMs + 40);
}
}
/* ── Autoplay ── */
function startAuto () { autoTm = setInterval(advance, CFG.autoMs); }
function stopAuto () { clearInterval(autoTm); }
function resetAuto () { stopAuto(); startAuto(); }
/* Pausa en hover */
slider.addEventListener('mouseenter', stopAuto);
slider.addEventListener('mouseleave', startAuto);
/* ── Drag mouse ── */
track.addEventListener('mousedown', function (e) {
if (busy) return;
dragX = e.clientX;
isDrag = true;
});
document.addEventListener('mousemove', function (e) {
if (!isDrag) return;
if (Math.abs(e.clientX - dragX) > 6) track.style.cursor = 'grabbing';
});
document.addEventListener('mouseup', function (e) {
if (!isDrag) return;
isDrag = false;
track.style.cursor = '';
var d = e.clientX - dragX;
if (d < -50) advance();
else if (d > 50) retreat();
resetAuto();
});
/* ── Touch móvil ── */
track.addEventListener('touchstart', function (e) {
tX = e.touches[0].clientX;
}, { passive: true });
track.addEventListener('touchmove', function (e) {
e.preventDefault();
}, { passive: false });
track.addEventListener('touchend', function (e) {
var d = e.changedTouches[0].clientX - tX;
if (d < -45) advance();
else if (d > 45) retreat();
resetAuto();
});
/* ── Resize ── */
var rTm;
window.addEventListener('resize', function () {
clearTimeout(rTm);
rTm = setTimeout(function () { applyPos(off(cur), false); }, 120);
});
/* ── Inicio ── */
applyPos(0, false);
updateUI();
startAuto();
}
/* ── Compatibilidad Elementor Pro:
- jQuery ready: garantiza que el DOM del widget esté listo
- elementor/frontend/init: re-init al previsualizar en el editor ── */
$(document).ready(function () {
init();
$(window).on('elementor/frontend/init', function () { init(); });
});
}(jQuery));