DESCOPERĂ CATEGORIA
Mobilier Living
Aspectele privind confidențialitatea și prelucrarea datelor cu caracter personal legate de utilizarea site-ului technefurniture.com sunt guvernate de Politică de confidențialitate revizuită conform cerințelor GDPR – Regulamentului (UE) 2016/679 privind protecț.
Alege dintre +50.000 de produse
Descoperă categoria
În stoc
Dulap maro/negru din lemn Nairobi Dutchbone
În stoc
Dulap maro/negru din lemn Nairobi Dutchbone
În stoc
Dulap maro/negru din lemn Nairobi Dutchbone
DESCOPERĂ CATEGORIA
Mobilier Living
Aspectele privind confidențialitatea și prelucrarea datelor cu caracter personal legate de utilizarea site-ului technefurniture.com sunt guvernate de Politică de confidențialitate revizuită conform cerințelor GDPR – Regulamentului (UE) 2016/679 privind protecț.
Alege dintre +50.000 de produse
Descoperă categoria
În stoc
Dulap maro/negru din lemn Nairobi Dutchbone
În stoc
Dulap maro/negru din lemn Nairobi Dutchbone
În stoc
Dulap maro/negru din lemn Nairobi Dutchbone
DESCOPERĂ CATEGORIA
Mobilier Living
Aspectele privind confidențialitatea și prelucrarea datelor cu caracter personal legate de utilizarea site-ului technefurniture.com sunt guvernate de Politică de confidențialitate revizuită conform cerințelor GDPR – Regulamentului (UE) 2016/679 privind protecț.
Alege dintre +50.000 de produse
Descoperă categoria
În stoc
Dulap maro/negru din lemn Nairobi Dutchbone
În stoc
Dulap maro/negru din lemn Nairobi Dutchbone
În stoc
Dulap maro/negru din lemn Nairobi Dutchbone
La tine în 3 zile
Montare rapidă
La tine în 3 zile
Montare rapidă
La tine în 3 zile
Montare rapidă
La tine în 3 zile
Montare rapidă
La tine în 3 zile
Montare rapidă
La tine în 3 zile
Montare rapidă
Camere
Bucură-te de ofertele noastre
Mobilier dormitor
Paturi tapițate
•
Noptiere
•
Comode
Dressinguri
•
Alta Subcategorie
Mobilier dormitor
Paturi tapițate
•
Noptiere
•
Comode
Dressinguri
•
Alta Subcategorie
Mobilier dormitor
Paturi tapițate
•
Noptiere
•
Comode
Dressinguri
•
Alta Subcategorie
Mobilier dormitor
Paturi tapițate
•
Noptiere
•
Comode
Dressinguri
•
Alta Subcategorie
Mobilier dormitor
Paturi tapițate
•
Noptiere
•
Comode
Dressinguri
•
Alta Subcategorie
Reduceri Speciale
Aplică codul SPEED20 pentru -20% reducere
<style>
/* Ascunde complet sliderul PÂNĂ e 100% montat (fără fade/blink) */
#brxe-simbdl.vh-mask {
opacity: 0 !important;
visibility: hidden !important;
pointer-events: none !important;
}
/* Prelayout: imităm EXACT ce va face Splide după mount,
ca să nu existe schimbare vizuală la gap/înălțime */
#brxe-simbdl.vh-prelayout .splide__list {
display: flex;
}
#brxe-simbdl.vh-prelayout .splide__slide {
margin-right: var(--vh-gap, 1.3vw);
min-height: var(--vh-minh, 36rem);
}
</style>
<script>
(function(){
const SPLIDE_ROOT_ID = 'brxe-simbdl'; // <-- schimbi pt instanța 2
const FILTER_SELECT_ID = 'brxe-zuequz'; // <-- schimbi pt instanța 2
const PRICE_ANIMATIONS = false;
const HOVER_PREFETCH = true;
function onReady(fn){
if(document.readyState==='loading'){
document.addEventListener('DOMContentLoaded', fn,{once:true});
} else {
fn();
}
}
function getApiRoot(){
return (window.wpApiSettings && window.wpApiSettings.root) || '/wp-json/';
}
async function fetchVariationData(variationId, decimals){
const url = getApiRoot() + 'my/v1/variation-discount/' + encodeURIComponent(variationId) + '?decimals=' + (decimals ?? 0);
const res = await fetch(url, { credentials:'same-origin' });
if(!res.ok) throw new Error('HTTP '+res.status);
return res.json();
}
const forEach = (nl, cb)=> Array.prototype.forEach.call(nl, cb);
const isClone = el => !!el.closest('.splide__slide--clone');
function ensureShown(el){
if(el && getComputedStyle(el).display==='none'){
el.style.setProperty('display','flex','important');
}
}
function nfRON(val){
if(val==null||val==='') return '';
const n=Number(val);
if(!Number.isFinite(n)) return '';
return new Intl.NumberFormat('ro-RO',{minimumFractionDigits:0,maximumFractionDigits:2}).format(n)+' RON';
}
function stockTextRo(s){
return s==='instock'?'În stoc'
:s==='outofstock'?'Stoc epuizat'
:s==='onbackorder'?'În stoc furnizor'
:'';
}
function stockColor(s){
return s==='instock' ?'#00E832'
:s==='outofstock' ?'#FF0000'
:s==='onbackorder' ?'#ffb22e'
:'#9ca3af';
}
function formatDim(v,u){
if(v==null||v==='') return '';
return `${v}${u||''}`.trim();
}
function getFullUrlFromItem(item){
if(!item) return '';
const d=item.getAttribute('data-url'); if(d) return d;
const a=item.querySelector('a[href]'); if(a&&a.href) return a.href;
const img=item.querySelector('img'); if(img) return img.currentSrc||img.src||'';
return '';
}
const _barTimers=new WeakMap(), _hideTimers=new WeakMap();
function cancelOldBar(el){
const t=_barTimers.get(el);
if(t){clearTimeout(t);_barTimers.delete(el);}
}
function animateOldPriceBar(barEl){
if (!PRICE_ANIMATIONS || !barEl) return;
const t = barEl.style.transition;
if (!t || !/min-width/.test(t)){
barEl.style.transition = 'min-width .2s ease-in-out';
}
barEl.style.minWidth = '0%';
void barEl.offsetWidth;
barEl.style.minWidth = '110%';
}
function scheduleOldBar(el){
if(!PRICE_ANIMATIONS) return;
cancelOldBar(el);
const t=setTimeout(()=>{
animateOldPriceBar(el);
_barTimers.delete(el);
}, 0);
_barTimers.set(el,t);
}
function _scheduleHide(el,ms){
if(!PRICE_ANIMATIONS){
el.style.opacity=0;
return;
}
if(!el) return;
_cancelHide(el);
const t=setTimeout(()=>{
el.style.opacity=0;
_hideTimers.delete(el);
},ms);
_hideTimers.set(el,t);
}
function _cancelHide(el){
const t=_hideTimers.get(el);
if(t){clearTimeout(t);_hideTimers.delete(el);}
}
function hideOldPrice(el,delay){
if(!el) return;
if(PRICE_ANIMATIONS && delay>0){
_scheduleHide(el,delay);
} else {
_cancelHide(el);
el.style.opacity=0;
}
}
function showOldPrice(el){
if(!el) return;
_cancelHide(el);
ensureShown(el);
el.style.opacity=1;
}
function updateDiscountBox(card,p){
const box=card.querySelector('.reducere-produs-shop');
const text=card.querySelector('.text-reducere-produs-shop');
if(!box||!text) return;
if(!p||p.discount_percent==null){
box.style.opacity=0;
return;
}
const v='-'+p.discount_percent+'%';
if(text.textContent!==v) text.textContent=v;
ensureShown(box);
box.style.opacity=1;
}
function updateStockBox(card,p){
const wrap=card.querySelector('.stoc-produs-shop');
const dot=card.querySelector('.punct-stoc-produs-shop');
const txt=card.querySelector('.text-stoc-produs-shop');
if(!wrap||!dot||!txt) return;
const status=p&&p.stock_status?String(p.stock_status):'';
const label=stockTextRo(status);
if(!label){
wrap.classList.remove('is-visible');
if(txt.textContent) txt.textContent='';
return;
}
if(txt.textContent!==label) txt.textContent=label;
const c=stockColor(status);
if(dot.style.backgroundColor!==c) dot.style.backgroundColor=c;
ensureShown(wrap);
wrap.classList.add('is-visible');
}
function updateDimensions(card,p){
const l=card.querySelector('.text-lungime-produs-shop');
const w=card.querySelector('.text-adancime-produs-shop');
const h=card.querySelector('.text-inaltime-produs-shop');
if(!l && !w && !h) return;
const unit=p&&p.dimension_unit?String(p.dimension_unit):'';
const L=p?p.length:null, W=p?p.width:null, H=p?p.height:null;
if(l){ const v=formatDim(L,unit); if(l.textContent!==v) l.textContent=v; }
if(w){ const v=formatDim(W,unit); if(w.textContent!==v) w.textContent=v; }
if(h){ const v=formatDim(H,unit); if(h.textContent!==v) h.textContent=v; }
}
function updatePrices(card,p){
const actual=card.querySelector('.pret-actual-produs-shop');
const oldWrap=card.querySelector('.wrap-pret-vechi-produs-shop');
const oldText=card.querySelector('.pret-vechi-produs-shop');
const oldBar =card.querySelector('.div-pret-vechi-produs-shop');
if(!actual) return;
const reg = p && p.regular_price!=null ? p.regular_price : null;
const sale= p && p.sale_price !=null ? p.sale_price : null;
// niciun preț valid
if(reg==null && sale==null){
if(actual.textContent) actual.textContent='';
if(oldWrap) hideOldPrice(oldWrap,0);
if(oldBar){
cancelOldBar(oldBar);
oldBar.style.minWidth='0%';
}
if(oldText&&oldText.textContent) oldText.textContent='';
return;
}
// există reducere reală
if(sale!=null && reg!=null && +sale>0 && +reg>0 && +sale<+reg){
const cur=nfRON(sale);
if(actual.textContent!==cur) actual.textContent=cur;
if(oldWrap) showOldPrice(oldWrap);
const regTxt=nfRON(reg);
if(oldText && oldText.textContent!==regTxt) oldText.textContent=regTxt;
if(oldBar){
cancelOldBar(oldBar);
if (PRICE_ANIMATIONS) {
scheduleOldBar(oldBar);
} else {
// fără animații -> fă bara vizibilă din nou
oldBar.style.minWidth = '110%';
}
}
return;
}
// fără reducere -> afișăm doar prețul normal și ascundem bara veche
const cur=nfRON(reg!=null?reg:sale);
if(actual.textContent!==cur) actual.textContent=cur;
if(oldBar){
cancelOldBar(oldBar);
oldBar.style.minWidth='0%';
}
if(oldWrap){
hideOldPrice(oldWrap, PRICE_ANIMATIONS ? 200 : 0);
}
}
function setMainImage(card, url){
const main=card.querySelector('[data-main-image]');
if(!main||!url) return;
if(main.dataset.mainSrc===url) return;
const pre=new Image();
pre.onload=function(){
if(main.dataset.mainSrc===url) return;
if(main.tagName==='IMG'){
main.setAttribute('src',url);
} else {
main.style.backgroundImage='url("'+url+'")';
}
main.dataset.mainSrc=url;
};
pre.src=url;
}
function setActiveItem(card, active){
forEach(card.querySelectorAll('[data-variation-item]'), el=>{
const act=el===active;
el.classList.toggle('is-active',act);
el.setAttribute('aria-selected', act?'true':'false');
});
}
const variationCache=new Map();
const prefetchQueue=new Set();
async function prefetchIds(ids){
const tasks=[];
ids.forEach(id=>{
if(!id) return;
if(!variationCache.has(id) && !prefetchQueue.has(id)){
prefetchQueue.add(id);
tasks.push(
fetchVariationData(id,0)
.then(d=>variationCache.set(id,d))
.catch(()=>variationCache.set(id,null))
.finally(()=>prefetchQueue.delete(id))
);
}
});
if(tasks.length) await Promise.allSettled(tasks);
}
async function prefetchAllIn(container){
const ids=new Set(
Array.from(container.querySelectorAll('[data-variation-item][data-variation-id]'))
.filter(el=>!isClone(el))
.map(el=>el.getAttribute('data-variation-id'))
.filter(Boolean)
);
await prefetchIds(ids);
}
async function initCard(card){
if(!card || card.dataset.init==='1') return;
if(isClone(card)) return;
card.dataset.init='1';
const firstItem=card.querySelector('[data-variation-item][data-variation-id]');
if(!firstItem) return;
setActiveItem(card, firstItem);
const vid=firstItem.getAttribute('data-variation-id');
const cached=variationCache.get(vid);
if(cached!==undefined){
updateDiscountBox(card,cached);
updateStockBox(card,cached);
updateDimensions(card,cached);
updatePrices(card,cached);
} else {
try{
const data=await fetchVariationData(vid,0);
variationCache.set(vid,data);
updateDiscountBox(card,data);
updateStockBox(card,data);
updateDimensions(card,data);
updatePrices(card,data);
}catch(e){
variationCache.set(vid, null);
}
}
const firstUrl=getFullUrlFromItem(firstItem);
if(firstUrl) setMainImage(card, firstUrl);
}
function initAllCards(root){
forEach((root||document).querySelectorAll('[data-product-card]'), card=>initCard(card));
}
// ==== SPLIDE MANAGER PER INSTANȚĂ ====
let ownSplide=null;
let rebuilding=false;
function getRoot(){
return document.getElementById(SPLIDE_ROOT_ID);
}
function readBricksOptions(rootEl){
try{
const raw=rootEl.getAttribute('data-splide');
if(!raw) return {};
const opts=JSON.parse(raw);
return Object.assign({ type:'slide', speed:400, perPage:4, gap:'1.3vw', autoHeight:false }, opts);
}catch(e){
return { type:'slide', gap:'1.3vw', autoHeight:false };
}
}
function detachBricksInstance(rootEl){
if(!rootEl) return;
const map = (window.bricksData && window.bricksData.splideInstances) || null;
if(map){
for(const k of Object.keys(map)){
const inst = map[k];
if(inst && (inst.root===rootEl || inst.root?.id===rootEl.id)){
try{ inst.destroy && inst.destroy(true); }catch(e){}
map[k]=null;
}
}
}
if(!rootEl.dataset.vh_splide_opts){
const opts = readBricksOptions(rootEl);
rootEl.dataset.vh_splide_opts = JSON.stringify(opts);
}
rootEl.removeAttribute('data-splide');
rootEl.classList.add('vh-splide-locked');
}
function resetInline(rootEl){
const track=rootEl.querySelector('.splide__track');
const list =rootEl.querySelector('.splide__list');
const slides=rootEl.querySelectorAll('.splide__slide');
if(track){ track.style.height=''; track.style.transform=''; }
if(list ){ list.style.height=''; list.style.transform=''; list.style.gap=''; }
slides.forEach(sl=>{
sl.style.height='';
sl.style.minHeight='';
sl.style.margin='';
});
}
function ensureStructure(rootEl){
let track = rootEl.querySelector('.splide__track');
let list = rootEl.querySelector('.splide__list');
if(!track){
track = document.createElement('div');
track.className='splide__track';
while(rootEl.firstChild) track.appendChild(rootEl.firstChild);
rootEl.appendChild(track);
}
if(!list){
list = document.createElement('ul');
list.className='splide__list';
const children = Array.from(track.children);
children.forEach(ch=>{
const li=document.createElement('li');
li.className='splide__slide';
li.appendChild(ch);
list.appendChild(li);
});
track.innerHTML='';
track.appendChild(list);
}
const kids = Array.from(list.children);
kids.forEach(li=>{
if(!li.classList.contains('splide__slide')){
li.classList.add('splide__slide');
}
});
list.querySelectorAll('.splide__slide--clone').forEach(c=>c.remove());
return {track, list};
}
function lockVisual(rootEl){
if (!rootEl) return;
const opts = (()=>{
try{ return JSON.parse(rootEl.dataset.vh_splide_opts || '{}'); } catch(e){ return {}; }
})();
rootEl.style.setProperty('--vh-gap', (opts.gap || '1.3vw'));
if (opts.fixedHeight) rootEl.style.setProperty('--vh-minh', opts.fixedHeight);
// ascundem până terminăm rebuild-ul
rootEl.style.setProperty('opacity', '0', 'important');
rootEl.style.setProperty('visibility', 'hidden', 'important');
rootEl.style.setProperty('pointer-events', 'none', 'important');
rootEl.classList.add('vh-prelayout','vh-mask');
}
function unlockVisual(rootEl){
if (!rootEl) return;
rootEl.style.removeProperty('opacity');
rootEl.style.removeProperty('visibility');
rootEl.style.removeProperty('pointer-events');
rootEl.classList.remove('vh-mask','vh-prelayout');
}
async function buildSplide(){
const rootEl=getRoot();
if(!rootEl || !window.Splide) return;
if(rebuilding) return;
rebuilding = true;
lockVisual(rootEl);
detachBricksInstance(rootEl);
resetInline(rootEl);
ensureStructure(rootEl);
const opts = (()=>{
try{ return JSON.parse(rootEl.dataset.vh_splide_opts || '{}'); } catch(e){ return {}; }
})();
if(ownSplide){
try{ ownSplide.destroy(true); }catch(e){}
ownSplide=null;
}
ownSplide = new Splide(rootEl, opts);
ownSplide.mount();
// stabilizare într-un frame înainte să-l arătăm
await new Promise(r=>requestAnimationFrame(()=>r()));
ownSplide.refresh();
ownSplide.emit && ownSplide.emit('resize');
unlockVisual(rootEl);
if(!window.bricksData) window.bricksData = {};
if(!window.bricksData.splideInstances) window.bricksData.splideInstances = {};
window.bricksData.splideInstances[SPLIDE_ROOT_ID + '__own'] = ownSplide;
rebuilding = false;
}
// debounce rebuild cu token, ca să nu dăm rebuild de 2 ori
let rebuildToken = 0;
let rebuildTimerRef = null;
function rebuildSplideDebounced(delay=100){
const myToken = ++rebuildToken;
if(rebuildTimerRef) clearTimeout(rebuildTimerRef);
rebuildTimerRef = setTimeout(()=>{
if(myToken !== rebuildToken) return;
buildSplide();
}, delay);
}
// ====== Variation click (schimbă variantă + UI card) ======
function onClickVariation(e){
const item=e.target.closest && e.target.closest('[data-variation-item][data-variation-id]');
if(!item) return;
const a=e.target.closest('a');
if(a && item.contains(a)) e.preventDefault();
const card=item.closest('[data-product-card]');
if(!card || isClone(card)) return;
const vid=item.getAttribute('data-variation-id');
setActiveItem(card,item);
const data=variationCache.get(vid);
if(data!==undefined){
updateDiscountBox(card,data);
updateStockBox(card,data);
updateDimensions(card,data);
updatePrices(card,data);
} else {
fetchVariationData(vid,0).then(d=>{
variationCache.set(vid,d);
updateDiscountBox(card,d);
updateStockBox(card,d);
updateDimensions(card,d);
updatePrices(card,d);
}).catch(()=>{
variationCache.set(vid,null);
});
// prefetch pentru restul variantelor din același card
const siblings = Array.from(
card.querySelectorAll('[data-variation-item][data-variation-id]')
).map(el=>el.getAttribute('data-variation-id'));
prefetchIds(new Set(siblings));
}
const fullUrl=getFullUrlFromItem(item);
if(fullUrl) setMainImage(card, fullUrl);
}
function attachHoverPrefetch(){
if(!HOVER_PREFETCH) return;
if(document.body.dataset.vhHoverBound==='1') return;
document.body.dataset.vhHoverBound='1';
document.addEventListener('mouseenter', e=>{
const it = e.target.closest && e.target.closest('[data-variation-item][data-variation-id]');
if(!it) return;
const vid = it.getAttribute('data-variation-id');
if(vid && !variationCache.has(vid)){
prefetchIds(new Set([vid]));
}
}, true);
}
// ====== Filter & observer ======
// stare doar pt sliderul ăsta
let awaitingDom = false;
let awaitingFallback= null;
let mo = null;
function attachFilterWatcher(){
const sel=document.getElementById(FILTER_SELECT_ID);
if(!sel || sel.dataset.vhBound==='1') return;
sel.dataset.vhBound='1';
sel.addEventListener('change', ()=>{
const rootEl=getRoot();
if(rootEl) lockVisual(rootEl); // ascundem sliderul vechi instant
awaitingDom = true; // așteptăm noul DOM după filtrare
// fallback dacă Bricks reordonează fără să schimbe nodurile într-un mod care declanșează observerul
if(awaitingFallback) clearTimeout(awaitingFallback);
awaitingFallback = setTimeout(()=>{
if(awaitingDom){
awaitingDom = false;
rebuildSplideDebounced(0);
}
}, 900);
// refacem cardurile după ce Bricks a actualizat conținutul intern
setTimeout(async ()=>{
const root=getRoot();
if(root){
const cont = root.querySelector('.splide__list') || root;
await prefetchAllIn(cont);
initAllCards(document);
}
}, 30);
});
}
function startObserver(){
if(mo) return;
mo=new MutationObserver((mut)=>{
const rootEl = getRoot();
if(!rootEl) return;
let touch = false;
let addedRoot = null;
for(const m of mut){
if(m.type!=='childList') continue;
// verificăm DOAR mutații care ating sliderul ăsta
m.addedNodes && m.addedNodes.forEach(n=>{
if(n.nodeType!==1) return;
// 1) dacă nodul adăugat ESTE chiar root-ul meu
if(n === rootEl){
touch=true;
addedRoot=rootEl;
return;
}
// 2) dacă nodul adăugat CONȚINE root-ul meu
if(n.contains && n.contains(rootEl)){
touch=true;
addedRoot=rootEl;
return;
}
// 3) dacă root-ul meu conține nodul adăugat (s-a schimbat conținutul intern al sliderului meu)
if(rootEl.contains(n)){
touch=true;
addedRoot=rootEl;
return;
}
});
}
if(!touch) return; // ignora mutațiile altor slider-e
// Am detectat modificare relevantă PENTRU sliderul acesta
const activeRoot = addedRoot || rootEl;
if(activeRoot) lockVisual(activeRoot); // îl ascundem până terminăm rebuild
if(awaitingDom){
// era un refresh de filtrare pentru sliderul ăsta
awaitingDom = false;
if(awaitingFallback){
clearTimeout(awaitingFallback);
awaitingFallback=null;
}
rebuildSplideDebounced(60); // rebuild rapid pt sliderul ăsta
} else {
// doar o mică mutație (ex. resize/reflow etc.)
rebuildSplideDebounced(100);
}
// re-init la carduri după ce DOM-ul nou e acolo
setTimeout(()=>initAllCards(document), 20);
});
// Observăm tot body-ul, dar în callback filtrăm strict pe root-ul ăsta
mo.observe(document.body,{childList:true,subtree:true});
}
// ====== ENTRY POINT ======
onReady(async function(){
const root0 = getRoot();
if (root0) await prefetchAllIn(root0);
initAllCards(document);
if(!document.body.dataset.vhClickBound){
document.addEventListener('click', onClickVariation);
document.body.dataset.vhClickBound='1';
}
attachHoverPrefetch();
attachFilterWatcher();
startObserver();
if(root0){
const opts = readBricksOptions(root0);
root0.style.setProperty('--vh-gap', (opts.gap || '1.3vw'));
if (opts.fixedHeight) root0.style.setProperty('--vh-minh', opts.fixedHeight);
}
buildSplide();
window.addEventListener('resize', ()=>{
rebuildSplideDebounced(100);
}, {passive:true});
});
})();
</script>
asf
L
90cm
I
90cm
A
90cm
976 RON
976 RON
Aplică codul SPEED20 pentru -20% reducere
<style>
/* Ascunde complet sliderul PÂNĂ e 100% montat (fără fade/blink) */
#brxe-simbdl.vh-mask {
opacity: 0 !important;
visibility: hidden !important;
pointer-events: none !important;
}
/* Prelayout: imităm EXACT ce va face Splide după mount,
ca să nu existe schimbare vizuală la gap/înălțime */
#brxe-simbdl.vh-prelayout .splide__list {
display: flex;
}
#brxe-simbdl.vh-prelayout .splide__slide {
margin-right: var(--vh-gap, 1.3vw);
min-height: var(--vh-minh, 36rem);
}
</style>
<script>
(function(){
const SPLIDE_ROOT_ID = 'brxe-simbdl'; // <-- schimbi pt instanța 2
const FILTER_SELECT_ID = 'brxe-zuequz'; // <-- schimbi pt instanța 2
const PRICE_ANIMATIONS = false;
const HOVER_PREFETCH = true;
function onReady(fn){
if(document.readyState==='loading'){
document.addEventListener('DOMContentLoaded', fn,{once:true});
} else {
fn();
}
}
function getApiRoot(){
return (window.wpApiSettings && window.wpApiSettings.root) || '/wp-json/';
}
async function fetchVariationData(variationId, decimals){
const url = getApiRoot() + 'my/v1/variation-discount/' + encodeURIComponent(variationId) + '?decimals=' + (decimals ?? 0);
const res = await fetch(url, { credentials:'same-origin' });
if(!res.ok) throw new Error('HTTP '+res.status);
return res.json();
}
const forEach = (nl, cb)=> Array.prototype.forEach.call(nl, cb);
const isClone = el => !!el.closest('.splide__slide--clone');
function ensureShown(el){
if(el && getComputedStyle(el).display==='none'){
el.style.setProperty('display','flex','important');
}
}
function nfRON(val){
if(val==null||val==='') return '';
const n=Number(val);
if(!Number.isFinite(n)) return '';
return new Intl.NumberFormat('ro-RO',{minimumFractionDigits:0,maximumFractionDigits:2}).format(n)+' RON';
}
function stockTextRo(s){
return s==='instock'?'În stoc'
:s==='outofstock'?'Stoc epuizat'
:s==='onbackorder'?'În stoc furnizor'
:'';
}
function stockColor(s){
return s==='instock' ?'#00E832'
:s==='outofstock' ?'#FF0000'
:s==='onbackorder' ?'#ffb22e'
:'#9ca3af';
}
function formatDim(v,u){
if(v==null||v==='') return '';
return `${v}${u||''}`.trim();
}
function getFullUrlFromItem(item){
if(!item) return '';
const d=item.getAttribute('data-url'); if(d) return d;
const a=item.querySelector('a[href]'); if(a&&a.href) return a.href;
const img=item.querySelector('img'); if(img) return img.currentSrc||img.src||'';
return '';
}
const _barTimers=new WeakMap(), _hideTimers=new WeakMap();
function cancelOldBar(el){
const t=_barTimers.get(el);
if(t){clearTimeout(t);_barTimers.delete(el);}
}
function animateOldPriceBar(barEl){
if (!PRICE_ANIMATIONS || !barEl) return;
const t = barEl.style.transition;
if (!t || !/min-width/.test(t)){
barEl.style.transition = 'min-width .2s ease-in-out';
}
barEl.style.minWidth = '0%';
void barEl.offsetWidth;
barEl.style.minWidth = '110%';
}
function scheduleOldBar(el){
if(!PRICE_ANIMATIONS) return;
cancelOldBar(el);
const t=setTimeout(()=>{
animateOldPriceBar(el);
_barTimers.delete(el);
}, 0);
_barTimers.set(el,t);
}
function _scheduleHide(el,ms){
if(!PRICE_ANIMATIONS){
el.style.opacity=0;
return;
}
if(!el) return;
_cancelHide(el);
const t=setTimeout(()=>{
el.style.opacity=0;
_hideTimers.delete(el);
},ms);
_hideTimers.set(el,t);
}
function _cancelHide(el){
const t=_hideTimers.get(el);
if(t){clearTimeout(t);_hideTimers.delete(el);}
}
function hideOldPrice(el,delay){
if(!el) return;
if(PRICE_ANIMATIONS && delay>0){
_scheduleHide(el,delay);
} else {
_cancelHide(el);
el.style.opacity=0;
}
}
function showOldPrice(el){
if(!el) return;
_cancelHide(el);
ensureShown(el);
el.style.opacity=1;
}
function updateDiscountBox(card,p){
const box=card.querySelector('.reducere-produs-shop');
const text=card.querySelector('.text-reducere-produs-shop');
if(!box||!text) return;
if(!p||p.discount_percent==null){
box.style.opacity=0;
return;
}
const v='-'+p.discount_percent+'%';
if(text.textContent!==v) text.textContent=v;
ensureShown(box);
box.style.opacity=1;
}
function updateStockBox(card,p){
const wrap=card.querySelector('.stoc-produs-shop');
const dot=card.querySelector('.punct-stoc-produs-shop');
const txt=card.querySelector('.text-stoc-produs-shop');
if(!wrap||!dot||!txt) return;
const status=p&&p.stock_status?String(p.stock_status):'';
const label=stockTextRo(status);
if(!label){
wrap.classList.remove('is-visible');
if(txt.textContent) txt.textContent='';
return;
}
if(txt.textContent!==label) txt.textContent=label;
const c=stockColor(status);
if(dot.style.backgroundColor!==c) dot.style.backgroundColor=c;
ensureShown(wrap);
wrap.classList.add('is-visible');
}
function updateDimensions(card,p){
const l=card.querySelector('.text-lungime-produs-shop');
const w=card.querySelector('.text-adancime-produs-shop');
const h=card.querySelector('.text-inaltime-produs-shop');
if(!l && !w && !h) return;
const unit=p&&p.dimension_unit?String(p.dimension_unit):'';
const L=p?p.length:null, W=p?p.width:null, H=p?p.height:null;
if(l){ const v=formatDim(L,unit); if(l.textContent!==v) l.textContent=v; }
if(w){ const v=formatDim(W,unit); if(w.textContent!==v) w.textContent=v; }
if(h){ const v=formatDim(H,unit); if(h.textContent!==v) h.textContent=v; }
}
function updatePrices(card,p){
const actual=card.querySelector('.pret-actual-produs-shop');
const oldWrap=card.querySelector('.wrap-pret-vechi-produs-shop');
const oldText=card.querySelector('.pret-vechi-produs-shop');
const oldBar =card.querySelector('.div-pret-vechi-produs-shop');
if(!actual) return;
const reg = p && p.regular_price!=null ? p.regular_price : null;
const sale= p && p.sale_price !=null ? p.sale_price : null;
// niciun preț valid
if(reg==null && sale==null){
if(actual.textContent) actual.textContent='';
if(oldWrap) hideOldPrice(oldWrap,0);
if(oldBar){
cancelOldBar(oldBar);
oldBar.style.minWidth='0%';
}
if(oldText&&oldText.textContent) oldText.textContent='';
return;
}
// există reducere reală
if(sale!=null && reg!=null && +sale>0 && +reg>0 && +sale<+reg){
const cur=nfRON(sale);
if(actual.textContent!==cur) actual.textContent=cur;
if(oldWrap) showOldPrice(oldWrap);
const regTxt=nfRON(reg);
if(oldText && oldText.textContent!==regTxt) oldText.textContent=regTxt;
if(oldBar){
cancelOldBar(oldBar);
if (PRICE_ANIMATIONS) {
scheduleOldBar(oldBar);
} else {
// fără animații -> fă bara vizibilă din nou
oldBar.style.minWidth = '110%';
}
}
return;
}
// fără reducere -> afișăm doar prețul normal și ascundem bara veche
const cur=nfRON(reg!=null?reg:sale);
if(actual.textContent!==cur) actual.textContent=cur;
if(oldBar){
cancelOldBar(oldBar);
oldBar.style.minWidth='0%';
}
if(oldWrap){
hideOldPrice(oldWrap, PRICE_ANIMATIONS ? 200 : 0);
}
}
function setMainImage(card, url){
const main=card.querySelector('[data-main-image]');
if(!main||!url) return;
if(main.dataset.mainSrc===url) return;
const pre=new Image();
pre.onload=function(){
if(main.dataset.mainSrc===url) return;
if(main.tagName==='IMG'){
main.setAttribute('src',url);
} else {
main.style.backgroundImage='url("'+url+'")';
}
main.dataset.mainSrc=url;
};
pre.src=url;
}
function setActiveItem(card, active){
forEach(card.querySelectorAll('[data-variation-item]'), el=>{
const act=el===active;
el.classList.toggle('is-active',act);
el.setAttribute('aria-selected', act?'true':'false');
});
}
const variationCache=new Map();
const prefetchQueue=new Set();
async function prefetchIds(ids){
const tasks=[];
ids.forEach(id=>{
if(!id) return;
if(!variationCache.has(id) && !prefetchQueue.has(id)){
prefetchQueue.add(id);
tasks.push(
fetchVariationData(id,0)
.then(d=>variationCache.set(id,d))
.catch(()=>variationCache.set(id,null))
.finally(()=>prefetchQueue.delete(id))
);
}
});
if(tasks.length) await Promise.allSettled(tasks);
}
async function prefetchAllIn(container){
const ids=new Set(
Array.from(container.querySelectorAll('[data-variation-item][data-variation-id]'))
.filter(el=>!isClone(el))
.map(el=>el.getAttribute('data-variation-id'))
.filter(Boolean)
);
await prefetchIds(ids);
}
async function initCard(card){
if(!card || card.dataset.init==='1') return;
if(isClone(card)) return;
card.dataset.init='1';
const firstItem=card.querySelector('[data-variation-item][data-variation-id]');
if(!firstItem) return;
setActiveItem(card, firstItem);
const vid=firstItem.getAttribute('data-variation-id');
const cached=variationCache.get(vid);
if(cached!==undefined){
updateDiscountBox(card,cached);
updateStockBox(card,cached);
updateDimensions(card,cached);
updatePrices(card,cached);
} else {
try{
const data=await fetchVariationData(vid,0);
variationCache.set(vid,data);
updateDiscountBox(card,data);
updateStockBox(card,data);
updateDimensions(card,data);
updatePrices(card,data);
}catch(e){
variationCache.set(vid, null);
}
}
const firstUrl=getFullUrlFromItem(firstItem);
if(firstUrl) setMainImage(card, firstUrl);
}
function initAllCards(root){
forEach((root||document).querySelectorAll('[data-product-card]'), card=>initCard(card));
}
// ==== SPLIDE MANAGER PER INSTANȚĂ ====
let ownSplide=null;
let rebuilding=false;
function getRoot(){
return document.getElementById(SPLIDE_ROOT_ID);
}
function readBricksOptions(rootEl){
try{
const raw=rootEl.getAttribute('data-splide');
if(!raw) return {};
const opts=JSON.parse(raw);
return Object.assign({ type:'slide', speed:400, perPage:4, gap:'1.3vw', autoHeight:false }, opts);
}catch(e){
return { type:'slide', gap:'1.3vw', autoHeight:false };
}
}
function detachBricksInstance(rootEl){
if(!rootEl) return;
const map = (window.bricksData && window.bricksData.splideInstances) || null;
if(map){
for(const k of Object.keys(map)){
const inst = map[k];
if(inst && (inst.root===rootEl || inst.root?.id===rootEl.id)){
try{ inst.destroy && inst.destroy(true); }catch(e){}
map[k]=null;
}
}
}
if(!rootEl.dataset.vh_splide_opts){
const opts = readBricksOptions(rootEl);
rootEl.dataset.vh_splide_opts = JSON.stringify(opts);
}
rootEl.removeAttribute('data-splide');
rootEl.classList.add('vh-splide-locked');
}
function resetInline(rootEl){
const track=rootEl.querySelector('.splide__track');
const list =rootEl.querySelector('.splide__list');
const slides=rootEl.querySelectorAll('.splide__slide');
if(track){ track.style.height=''; track.style.transform=''; }
if(list ){ list.style.height=''; list.style.transform=''; list.style.gap=''; }
slides.forEach(sl=>{
sl.style.height='';
sl.style.minHeight='';
sl.style.margin='';
});
}
function ensureStructure(rootEl){
let track = rootEl.querySelector('.splide__track');
let list = rootEl.querySelector('.splide__list');
if(!track){
track = document.createElement('div');
track.className='splide__track';
while(rootEl.firstChild) track.appendChild(rootEl.firstChild);
rootEl.appendChild(track);
}
if(!list){
list = document.createElement('ul');
list.className='splide__list';
const children = Array.from(track.children);
children.forEach(ch=>{
const li=document.createElement('li');
li.className='splide__slide';
li.appendChild(ch);
list.appendChild(li);
});
track.innerHTML='';
track.appendChild(list);
}
const kids = Array.from(list.children);
kids.forEach(li=>{
if(!li.classList.contains('splide__slide')){
li.classList.add('splide__slide');
}
});
list.querySelectorAll('.splide__slide--clone').forEach(c=>c.remove());
return {track, list};
}
function lockVisual(rootEl){
if (!rootEl) return;
const opts = (()=>{
try{ return JSON.parse(rootEl.dataset.vh_splide_opts || '{}'); } catch(e){ return {}; }
})();
rootEl.style.setProperty('--vh-gap', (opts.gap || '1.3vw'));
if (opts.fixedHeight) rootEl.style.setProperty('--vh-minh', opts.fixedHeight);
// ascundem până terminăm rebuild-ul
rootEl.style.setProperty('opacity', '0', 'important');
rootEl.style.setProperty('visibility', 'hidden', 'important');
rootEl.style.setProperty('pointer-events', 'none', 'important');
rootEl.classList.add('vh-prelayout','vh-mask');
}
function unlockVisual(rootEl){
if (!rootEl) return;
rootEl.style.removeProperty('opacity');
rootEl.style.removeProperty('visibility');
rootEl.style.removeProperty('pointer-events');
rootEl.classList.remove('vh-mask','vh-prelayout');
}
async function buildSplide(){
const rootEl=getRoot();
if(!rootEl || !window.Splide) return;
if(rebuilding) return;
rebuilding = true;
lockVisual(rootEl);
detachBricksInstance(rootEl);
resetInline(rootEl);
ensureStructure(rootEl);
const opts = (()=>{
try{ return JSON.parse(rootEl.dataset.vh_splide_opts || '{}'); } catch(e){ return {}; }
})();
if(ownSplide){
try{ ownSplide.destroy(true); }catch(e){}
ownSplide=null;
}
ownSplide = new Splide(rootEl, opts);
ownSplide.mount();
// stabilizare într-un frame înainte să-l arătăm
await new Promise(r=>requestAnimationFrame(()=>r()));
ownSplide.refresh();
ownSplide.emit && ownSplide.emit('resize');
unlockVisual(rootEl);
if(!window.bricksData) window.bricksData = {};
if(!window.bricksData.splideInstances) window.bricksData.splideInstances = {};
window.bricksData.splideInstances[SPLIDE_ROOT_ID + '__own'] = ownSplide;
rebuilding = false;
}
// debounce rebuild cu token, ca să nu dăm rebuild de 2 ori
let rebuildToken = 0;
let rebuildTimerRef = null;
function rebuildSplideDebounced(delay=100){
const myToken = ++rebuildToken;
if(rebuildTimerRef) clearTimeout(rebuildTimerRef);
rebuildTimerRef = setTimeout(()=>{
if(myToken !== rebuildToken) return;
buildSplide();
}, delay);
}
// ====== Variation click (schimbă variantă + UI card) ======
function onClickVariation(e){
const item=e.target.closest && e.target.closest('[data-variation-item][data-variation-id]');
if(!item) return;
const a=e.target.closest('a');
if(a && item.contains(a)) e.preventDefault();
const card=item.closest('[data-product-card]');
if(!card || isClone(card)) return;
const vid=item.getAttribute('data-variation-id');
setActiveItem(card,item);
const data=variationCache.get(vid);
if(data!==undefined){
updateDiscountBox(card,data);
updateStockBox(card,data);
updateDimensions(card,data);
updatePrices(card,data);
} else {
fetchVariationData(vid,0).then(d=>{
variationCache.set(vid,d);
updateDiscountBox(card,d);
updateStockBox(card,d);
updateDimensions(card,d);
updatePrices(card,d);
}).catch(()=>{
variationCache.set(vid,null);
});
// prefetch pentru restul variantelor din același card
const siblings = Array.from(
card.querySelectorAll('[data-variation-item][data-variation-id]')
).map(el=>el.getAttribute('data-variation-id'));
prefetchIds(new Set(siblings));
}
const fullUrl=getFullUrlFromItem(item);
if(fullUrl) setMainImage(card, fullUrl);
}
function attachHoverPrefetch(){
if(!HOVER_PREFETCH) return;
if(document.body.dataset.vhHoverBound==='1') return;
document.body.dataset.vhHoverBound='1';
document.addEventListener('mouseenter', e=>{
const it = e.target.closest && e.target.closest('[data-variation-item][data-variation-id]');
if(!it) return;
const vid = it.getAttribute('data-variation-id');
if(vid && !variationCache.has(vid)){
prefetchIds(new Set([vid]));
}
}, true);
}
// ====== Filter & observer ======
// stare doar pt sliderul ăsta
let awaitingDom = false;
let awaitingFallback= null;
let mo = null;
function attachFilterWatcher(){
const sel=document.getElementById(FILTER_SELECT_ID);
if(!sel || sel.dataset.vhBound==='1') return;
sel.dataset.vhBound='1';
sel.addEventListener('change', ()=>{
const rootEl=getRoot();
if(rootEl) lockVisual(rootEl); // ascundem sliderul vechi instant
awaitingDom = true; // așteptăm noul DOM după filtrare
// fallback dacă Bricks reordonează fără să schimbe nodurile într-un mod care declanșează observerul
if(awaitingFallback) clearTimeout(awaitingFallback);
awaitingFallback = setTimeout(()=>{
if(awaitingDom){
awaitingDom = false;
rebuildSplideDebounced(0);
}
}, 900);
// refacem cardurile după ce Bricks a actualizat conținutul intern
setTimeout(async ()=>{
const root=getRoot();
if(root){
const cont = root.querySelector('.splide__list') || root;
await prefetchAllIn(cont);
initAllCards(document);
}
}, 30);
});
}
function startObserver(){
if(mo) return;
mo=new MutationObserver((mut)=>{
const rootEl = getRoot();
if(!rootEl) return;
let touch = false;
let addedRoot = null;
for(const m of mut){
if(m.type!=='childList') continue;
// verificăm DOAR mutații care ating sliderul ăsta
m.addedNodes && m.addedNodes.forEach(n=>{
if(n.nodeType!==1) return;
// 1) dacă nodul adăugat ESTE chiar root-ul meu
if(n === rootEl){
touch=true;
addedRoot=rootEl;
return;
}
// 2) dacă nodul adăugat CONȚINE root-ul meu
if(n.contains && n.contains(rootEl)){
touch=true;
addedRoot=rootEl;
return;
}
// 3) dacă root-ul meu conține nodul adăugat (s-a schimbat conținutul intern al sliderului meu)
if(rootEl.contains(n)){
touch=true;
addedRoot=rootEl;
return;
}
});
}
if(!touch) return; // ignora mutațiile altor slider-e
// Am detectat modificare relevantă PENTRU sliderul acesta
const activeRoot = addedRoot || rootEl;
if(activeRoot) lockVisual(activeRoot); // îl ascundem până terminăm rebuild
if(awaitingDom){
// era un refresh de filtrare pentru sliderul ăsta
awaitingDom = false;
if(awaitingFallback){
clearTimeout(awaitingFallback);
awaitingFallback=null;
}
rebuildSplideDebounced(60); // rebuild rapid pt sliderul ăsta
} else {
// doar o mică mutație (ex. resize/reflow etc.)
rebuildSplideDebounced(100);
}
// re-init la carduri după ce DOM-ul nou e acolo
setTimeout(()=>initAllCards(document), 20);
});
// Observăm tot body-ul, dar în callback filtrăm strict pe root-ul ăsta
mo.observe(document.body,{childList:true,subtree:true});
}
// ====== ENTRY POINT ======
onReady(async function(){
const root0 = getRoot();
if (root0) await prefetchAllIn(root0);
initAllCards(document);
if(!document.body.dataset.vhClickBound){
document.addEventListener('click', onClickVariation);
document.body.dataset.vhClickBound='1';
}
attachHoverPrefetch();
attachFilterWatcher();
startObserver();
if(root0){
const opts = readBricksOptions(root0);
root0.style.setProperty('--vh-gap', (opts.gap || '1.3vw'));
if (opts.fixedHeight) root0.style.setProperty('--vh-minh', opts.fixedHeight);
}
buildSplide();
window.addEventListener('resize', ()=>{
rebuildSplideDebounced(100);
}, {passive:true});
});
})();
</script>
asf
Masa cafea
In stoc
L
90cm
I
90cm
A
90cm
976 RON
976 RON
Aplică codul SPEED20 pentru -20% reducere
<style>
/* Ascunde complet sliderul PÂNĂ e 100% montat (fără fade/blink) */
#brxe-simbdl.vh-mask {
opacity: 0 !important;
visibility: hidden !important;
pointer-events: none !important;
}
/* Prelayout: imităm EXACT ce va face Splide după mount,
ca să nu existe schimbare vizuală la gap/înălțime */
#brxe-simbdl.vh-prelayout .splide__list {
display: flex;
}
#brxe-simbdl.vh-prelayout .splide__slide {
margin-right: var(--vh-gap, 1.3vw);
min-height: var(--vh-minh, 36rem);
}
</style>
<script>
(function(){
const SPLIDE_ROOT_ID = 'brxe-simbdl'; // <-- schimbi pt instanța 2
const FILTER_SELECT_ID = 'brxe-zuequz'; // <-- schimbi pt instanța 2
const PRICE_ANIMATIONS = false;
const HOVER_PREFETCH = true;
function onReady(fn){
if(document.readyState==='loading'){
document.addEventListener('DOMContentLoaded', fn,{once:true});
} else {
fn();
}
}
function getApiRoot(){
return (window.wpApiSettings && window.wpApiSettings.root) || '/wp-json/';
}
async function fetchVariationData(variationId, decimals){
const url = getApiRoot() + 'my/v1/variation-discount/' + encodeURIComponent(variationId) + '?decimals=' + (decimals ?? 0);
const res = await fetch(url, { credentials:'same-origin' });
if(!res.ok) throw new Error('HTTP '+res.status);
return res.json();
}
const forEach = (nl, cb)=> Array.prototype.forEach.call(nl, cb);
const isClone = el => !!el.closest('.splide__slide--clone');
function ensureShown(el){
if(el && getComputedStyle(el).display==='none'){
el.style.setProperty('display','flex','important');
}
}
function nfRON(val){
if(val==null||val==='') return '';
const n=Number(val);
if(!Number.isFinite(n)) return '';
return new Intl.NumberFormat('ro-RO',{minimumFractionDigits:0,maximumFractionDigits:2}).format(n)+' RON';
}
function stockTextRo(s){
return s==='instock'?'În stoc'
:s==='outofstock'?'Stoc epuizat'
:s==='onbackorder'?'În stoc furnizor'
:'';
}
function stockColor(s){
return s==='instock' ?'#00E832'
:s==='outofstock' ?'#FF0000'
:s==='onbackorder' ?'#ffb22e'
:'#9ca3af';
}
function formatDim(v,u){
if(v==null||v==='') return '';
return `${v}${u||''}`.trim();
}
function getFullUrlFromItem(item){
if(!item) return '';
const d=item.getAttribute('data-url'); if(d) return d;
const a=item.querySelector('a[href]'); if(a&&a.href) return a.href;
const img=item.querySelector('img'); if(img) return img.currentSrc||img.src||'';
return '';
}
const _barTimers=new WeakMap(), _hideTimers=new WeakMap();
function cancelOldBar(el){
const t=_barTimers.get(el);
if(t){clearTimeout(t);_barTimers.delete(el);}
}
function animateOldPriceBar(barEl){
if (!PRICE_ANIMATIONS || !barEl) return;
const t = barEl.style.transition;
if (!t || !/min-width/.test(t)){
barEl.style.transition = 'min-width .2s ease-in-out';
}
barEl.style.minWidth = '0%';
void barEl.offsetWidth;
barEl.style.minWidth = '110%';
}
function scheduleOldBar(el){
if(!PRICE_ANIMATIONS) return;
cancelOldBar(el);
const t=setTimeout(()=>{
animateOldPriceBar(el);
_barTimers.delete(el);
}, 0);
_barTimers.set(el,t);
}
function _scheduleHide(el,ms){
if(!PRICE_ANIMATIONS){
el.style.opacity=0;
return;
}
if(!el) return;
_cancelHide(el);
const t=setTimeout(()=>{
el.style.opacity=0;
_hideTimers.delete(el);
},ms);
_hideTimers.set(el,t);
}
function _cancelHide(el){
const t=_hideTimers.get(el);
if(t){clearTimeout(t);_hideTimers.delete(el);}
}
function hideOldPrice(el,delay){
if(!el) return;
if(PRICE_ANIMATIONS && delay>0){
_scheduleHide(el,delay);
} else {
_cancelHide(el);
el.style.opacity=0;
}
}
function showOldPrice(el){
if(!el) return;
_cancelHide(el);
ensureShown(el);
el.style.opacity=1;
}
function updateDiscountBox(card,p){
const box=card.querySelector('.reducere-produs-shop');
const text=card.querySelector('.text-reducere-produs-shop');
if(!box||!text) return;
if(!p||p.discount_percent==null){
box.style.opacity=0;
return;
}
const v='-'+p.discount_percent+'%';
if(text.textContent!==v) text.textContent=v;
ensureShown(box);
box.style.opacity=1;
}
function updateStockBox(card,p){
const wrap=card.querySelector('.stoc-produs-shop');
const dot=card.querySelector('.punct-stoc-produs-shop');
const txt=card.querySelector('.text-stoc-produs-shop');
if(!wrap||!dot||!txt) return;
const status=p&&p.stock_status?String(p.stock_status):'';
const label=stockTextRo(status);
if(!label){
wrap.classList.remove('is-visible');
if(txt.textContent) txt.textContent='';
return;
}
if(txt.textContent!==label) txt.textContent=label;
const c=stockColor(status);
if(dot.style.backgroundColor!==c) dot.style.backgroundColor=c;
ensureShown(wrap);
wrap.classList.add('is-visible');
}
function updateDimensions(card,p){
const l=card.querySelector('.text-lungime-produs-shop');
const w=card.querySelector('.text-adancime-produs-shop');
const h=card.querySelector('.text-inaltime-produs-shop');
if(!l && !w && !h) return;
const unit=p&&p.dimension_unit?String(p.dimension_unit):'';
const L=p?p.length:null, W=p?p.width:null, H=p?p.height:null;
if(l){ const v=formatDim(L,unit); if(l.textContent!==v) l.textContent=v; }
if(w){ const v=formatDim(W,unit); if(w.textContent!==v) w.textContent=v; }
if(h){ const v=formatDim(H,unit); if(h.textContent!==v) h.textContent=v; }
}
function updatePrices(card,p){
const actual=card.querySelector('.pret-actual-produs-shop');
const oldWrap=card.querySelector('.wrap-pret-vechi-produs-shop');
const oldText=card.querySelector('.pret-vechi-produs-shop');
const oldBar =card.querySelector('.div-pret-vechi-produs-shop');
if(!actual) return;
const reg = p && p.regular_price!=null ? p.regular_price : null;
const sale= p && p.sale_price !=null ? p.sale_price : null;
// niciun preț valid
if(reg==null && sale==null){
if(actual.textContent) actual.textContent='';
if(oldWrap) hideOldPrice(oldWrap,0);
if(oldBar){
cancelOldBar(oldBar);
oldBar.style.minWidth='0%';
}
if(oldText&&oldText.textContent) oldText.textContent='';
return;
}
// există reducere reală
if(sale!=null && reg!=null && +sale>0 && +reg>0 && +sale<+reg){
const cur=nfRON(sale);
if(actual.textContent!==cur) actual.textContent=cur;
if(oldWrap) showOldPrice(oldWrap);
const regTxt=nfRON(reg);
if(oldText && oldText.textContent!==regTxt) oldText.textContent=regTxt;
if(oldBar){
cancelOldBar(oldBar);
if (PRICE_ANIMATIONS) {
scheduleOldBar(oldBar);
} else {
// fără animații -> fă bara vizibilă din nou
oldBar.style.minWidth = '110%';
}
}
return;
}
// fără reducere -> afișăm doar prețul normal și ascundem bara veche
const cur=nfRON(reg!=null?reg:sale);
if(actual.textContent!==cur) actual.textContent=cur;
if(oldBar){
cancelOldBar(oldBar);
oldBar.style.minWidth='0%';
}
if(oldWrap){
hideOldPrice(oldWrap, PRICE_ANIMATIONS ? 200 : 0);
}
}
function setMainImage(card, url){
const main=card.querySelector('[data-main-image]');
if(!main||!url) return;
if(main.dataset.mainSrc===url) return;
const pre=new Image();
pre.onload=function(){
if(main.dataset.mainSrc===url) return;
if(main.tagName==='IMG'){
main.setAttribute('src',url);
} else {
main.style.backgroundImage='url("'+url+'")';
}
main.dataset.mainSrc=url;
};
pre.src=url;
}
function setActiveItem(card, active){
forEach(card.querySelectorAll('[data-variation-item]'), el=>{
const act=el===active;
el.classList.toggle('is-active',act);
el.setAttribute('aria-selected', act?'true':'false');
});
}
const variationCache=new Map();
const prefetchQueue=new Set();
async function prefetchIds(ids){
const tasks=[];
ids.forEach(id=>{
if(!id) return;
if(!variationCache.has(id) && !prefetchQueue.has(id)){
prefetchQueue.add(id);
tasks.push(
fetchVariationData(id,0)
.then(d=>variationCache.set(id,d))
.catch(()=>variationCache.set(id,null))
.finally(()=>prefetchQueue.delete(id))
);
}
});
if(tasks.length) await Promise.allSettled(tasks);
}
async function prefetchAllIn(container){
const ids=new Set(
Array.from(container.querySelectorAll('[data-variation-item][data-variation-id]'))
.filter(el=>!isClone(el))
.map(el=>el.getAttribute('data-variation-id'))
.filter(Boolean)
);
await prefetchIds(ids);
}
async function initCard(card){
if(!card || card.dataset.init==='1') return;
if(isClone(card)) return;
card.dataset.init='1';
const firstItem=card.querySelector('[data-variation-item][data-variation-id]');
if(!firstItem) return;
setActiveItem(card, firstItem);
const vid=firstItem.getAttribute('data-variation-id');
const cached=variationCache.get(vid);
if(cached!==undefined){
updateDiscountBox(card,cached);
updateStockBox(card,cached);
updateDimensions(card,cached);
updatePrices(card,cached);
} else {
try{
const data=await fetchVariationData(vid,0);
variationCache.set(vid,data);
updateDiscountBox(card,data);
updateStockBox(card,data);
updateDimensions(card,data);
updatePrices(card,data);
}catch(e){
variationCache.set(vid, null);
}
}
const firstUrl=getFullUrlFromItem(firstItem);
if(firstUrl) setMainImage(card, firstUrl);
}
function initAllCards(root){
forEach((root||document).querySelectorAll('[data-product-card]'), card=>initCard(card));
}
// ==== SPLIDE MANAGER PER INSTANȚĂ ====
let ownSplide=null;
let rebuilding=false;
function getRoot(){
return document.getElementById(SPLIDE_ROOT_ID);
}
function readBricksOptions(rootEl){
try{
const raw=rootEl.getAttribute('data-splide');
if(!raw) return {};
const opts=JSON.parse(raw);
return Object.assign({ type:'slide', speed:400, perPage:4, gap:'1.3vw', autoHeight:false }, opts);
}catch(e){
return { type:'slide', gap:'1.3vw', autoHeight:false };
}
}
function detachBricksInstance(rootEl){
if(!rootEl) return;
const map = (window.bricksData && window.bricksData.splideInstances) || null;
if(map){
for(const k of Object.keys(map)){
const inst = map[k];
if(inst && (inst.root===rootEl || inst.root?.id===rootEl.id)){
try{ inst.destroy && inst.destroy(true); }catch(e){}
map[k]=null;
}
}
}
if(!rootEl.dataset.vh_splide_opts){
const opts = readBricksOptions(rootEl);
rootEl.dataset.vh_splide_opts = JSON.stringify(opts);
}
rootEl.removeAttribute('data-splide');
rootEl.classList.add('vh-splide-locked');
}
function resetInline(rootEl){
const track=rootEl.querySelector('.splide__track');
const list =rootEl.querySelector('.splide__list');
const slides=rootEl.querySelectorAll('.splide__slide');
if(track){ track.style.height=''; track.style.transform=''; }
if(list ){ list.style.height=''; list.style.transform=''; list.style.gap=''; }
slides.forEach(sl=>{
sl.style.height='';
sl.style.minHeight='';
sl.style.margin='';
});
}
function ensureStructure(rootEl){
let track = rootEl.querySelector('.splide__track');
let list = rootEl.querySelector('.splide__list');
if(!track){
track = document.createElement('div');
track.className='splide__track';
while(rootEl.firstChild) track.appendChild(rootEl.firstChild);
rootEl.appendChild(track);
}
if(!list){
list = document.createElement('ul');
list.className='splide__list';
const children = Array.from(track.children);
children.forEach(ch=>{
const li=document.createElement('li');
li.className='splide__slide';
li.appendChild(ch);
list.appendChild(li);
});
track.innerHTML='';
track.appendChild(list);
}
const kids = Array.from(list.children);
kids.forEach(li=>{
if(!li.classList.contains('splide__slide')){
li.classList.add('splide__slide');
}
});
list.querySelectorAll('.splide__slide--clone').forEach(c=>c.remove());
return {track, list};
}
function lockVisual(rootEl){
if (!rootEl) return;
const opts = (()=>{
try{ return JSON.parse(rootEl.dataset.vh_splide_opts || '{}'); } catch(e){ return {}; }
})();
rootEl.style.setProperty('--vh-gap', (opts.gap || '1.3vw'));
if (opts.fixedHeight) rootEl.style.setProperty('--vh-minh', opts.fixedHeight);
// ascundem până terminăm rebuild-ul
rootEl.style.setProperty('opacity', '0', 'important');
rootEl.style.setProperty('visibility', 'hidden', 'important');
rootEl.style.setProperty('pointer-events', 'none', 'important');
rootEl.classList.add('vh-prelayout','vh-mask');
}
function unlockVisual(rootEl){
if (!rootEl) return;
rootEl.style.removeProperty('opacity');
rootEl.style.removeProperty('visibility');
rootEl.style.removeProperty('pointer-events');
rootEl.classList.remove('vh-mask','vh-prelayout');
}
async function buildSplide(){
const rootEl=getRoot();
if(!rootEl || !window.Splide) return;
if(rebuilding) return;
rebuilding = true;
lockVisual(rootEl);
detachBricksInstance(rootEl);
resetInline(rootEl);
ensureStructure(rootEl);
const opts = (()=>{
try{ return JSON.parse(rootEl.dataset.vh_splide_opts || '{}'); } catch(e){ return {}; }
})();
if(ownSplide){
try{ ownSplide.destroy(true); }catch(e){}
ownSplide=null;
}
ownSplide = new Splide(rootEl, opts);
ownSplide.mount();
// stabilizare într-un frame înainte să-l arătăm
await new Promise(r=>requestAnimationFrame(()=>r()));
ownSplide.refresh();
ownSplide.emit && ownSplide.emit('resize');
unlockVisual(rootEl);
if(!window.bricksData) window.bricksData = {};
if(!window.bricksData.splideInstances) window.bricksData.splideInstances = {};
window.bricksData.splideInstances[SPLIDE_ROOT_ID + '__own'] = ownSplide;
rebuilding = false;
}
// debounce rebuild cu token, ca să nu dăm rebuild de 2 ori
let rebuildToken = 0;
let rebuildTimerRef = null;
function rebuildSplideDebounced(delay=100){
const myToken = ++rebuildToken;
if(rebuildTimerRef) clearTimeout(rebuildTimerRef);
rebuildTimerRef = setTimeout(()=>{
if(myToken !== rebuildToken) return;
buildSplide();
}, delay);
}
// ====== Variation click (schimbă variantă + UI card) ======
function onClickVariation(e){
const item=e.target.closest && e.target.closest('[data-variation-item][data-variation-id]');
if(!item) return;
const a=e.target.closest('a');
if(a && item.contains(a)) e.preventDefault();
const card=item.closest('[data-product-card]');
if(!card || isClone(card)) return;
const vid=item.getAttribute('data-variation-id');
setActiveItem(card,item);
const data=variationCache.get(vid);
if(data!==undefined){
updateDiscountBox(card,data);
updateStockBox(card,data);
updateDimensions(card,data);
updatePrices(card,data);
} else {
fetchVariationData(vid,0).then(d=>{
variationCache.set(vid,d);
updateDiscountBox(card,d);
updateStockBox(card,d);
updateDimensions(card,d);
updatePrices(card,d);
}).catch(()=>{
variationCache.set(vid,null);
});
// prefetch pentru restul variantelor din același card
const siblings = Array.from(
card.querySelectorAll('[data-variation-item][data-variation-id]')
).map(el=>el.getAttribute('data-variation-id'));
prefetchIds(new Set(siblings));
}
const fullUrl=getFullUrlFromItem(item);
if(fullUrl) setMainImage(card, fullUrl);
}
function attachHoverPrefetch(){
if(!HOVER_PREFETCH) return;
if(document.body.dataset.vhHoverBound==='1') return;
document.body.dataset.vhHoverBound='1';
document.addEventListener('mouseenter', e=>{
const it = e.target.closest && e.target.closest('[data-variation-item][data-variation-id]');
if(!it) return;
const vid = it.getAttribute('data-variation-id');
if(vid && !variationCache.has(vid)){
prefetchIds(new Set([vid]));
}
}, true);
}
// ====== Filter & observer ======
// stare doar pt sliderul ăsta
let awaitingDom = false;
let awaitingFallback= null;
let mo = null;
function attachFilterWatcher(){
const sel=document.getElementById(FILTER_SELECT_ID);
if(!sel || sel.dataset.vhBound==='1') return;
sel.dataset.vhBound='1';
sel.addEventListener('change', ()=>{
const rootEl=getRoot();
if(rootEl) lockVisual(rootEl); // ascundem sliderul vechi instant
awaitingDom = true; // așteptăm noul DOM după filtrare
// fallback dacă Bricks reordonează fără să schimbe nodurile într-un mod care declanșează observerul
if(awaitingFallback) clearTimeout(awaitingFallback);
awaitingFallback = setTimeout(()=>{
if(awaitingDom){
awaitingDom = false;
rebuildSplideDebounced(0);
}
}, 900);
// refacem cardurile după ce Bricks a actualizat conținutul intern
setTimeout(async ()=>{
const root=getRoot();
if(root){
const cont = root.querySelector('.splide__list') || root;
await prefetchAllIn(cont);
initAllCards(document);
}
}, 30);
});
}
function startObserver(){
if(mo) return;
mo=new MutationObserver((mut)=>{
const rootEl = getRoot();
if(!rootEl) return;
let touch = false;
let addedRoot = null;
for(const m of mut){
if(m.type!=='childList') continue;
// verificăm DOAR mutații care ating sliderul ăsta
m.addedNodes && m.addedNodes.forEach(n=>{
if(n.nodeType!==1) return;
// 1) dacă nodul adăugat ESTE chiar root-ul meu
if(n === rootEl){
touch=true;
addedRoot=rootEl;
return;
}
// 2) dacă nodul adăugat CONȚINE root-ul meu
if(n.contains && n.contains(rootEl)){
touch=true;
addedRoot=rootEl;
return;
}
// 3) dacă root-ul meu conține nodul adăugat (s-a schimbat conținutul intern al sliderului meu)
if(rootEl.contains(n)){
touch=true;
addedRoot=rootEl;
return;
}
});
}
if(!touch) return; // ignora mutațiile altor slider-e
// Am detectat modificare relevantă PENTRU sliderul acesta
const activeRoot = addedRoot || rootEl;
if(activeRoot) lockVisual(activeRoot); // îl ascundem până terminăm rebuild
if(awaitingDom){
// era un refresh de filtrare pentru sliderul ăsta
awaitingDom = false;
if(awaitingFallback){
clearTimeout(awaitingFallback);
awaitingFallback=null;
}
rebuildSplideDebounced(60); // rebuild rapid pt sliderul ăsta
} else {
// doar o mică mutație (ex. resize/reflow etc.)
rebuildSplideDebounced(100);
}
// re-init la carduri după ce DOM-ul nou e acolo
setTimeout(()=>initAllCards(document), 20);
});
// Observăm tot body-ul, dar în callback filtrăm strict pe root-ul ăsta
mo.observe(document.body,{childList:true,subtree:true});
}
// ====== ENTRY POINT ======
onReady(async function(){
const root0 = getRoot();
if (root0) await prefetchAllIn(root0);
initAllCards(document);
if(!document.body.dataset.vhClickBound){
document.addEventListener('click', onClickVariation);
document.body.dataset.vhClickBound='1';
}
attachHoverPrefetch();
attachFilterWatcher();
startObserver();
if(root0){
const opts = readBricksOptions(root0);
root0.style.setProperty('--vh-gap', (opts.gap || '1.3vw'));
if (opts.fixedHeight) root0.style.setProperty('--vh-minh', opts.fixedHeight);
}
buildSplide();
window.addEventListener('resize', ()=>{
rebuildSplideDebounced(100);
}, {passive:true});
});
})();
</script>
asf
Canapea
In stoc
L
90cm
I
90cm
A
90cm
976 RON
976 RON
Aplică codul SPEED20 pentru -20% reducere
<style>
/* Ascunde complet sliderul PÂNĂ e 100% montat (fără fade/blink) */
#brxe-simbdl.vh-mask {
opacity: 0 !important;
visibility: hidden !important;
pointer-events: none !important;
}
/* Prelayout: imităm EXACT ce va face Splide după mount,
ca să nu existe schimbare vizuală la gap/înălțime */
#brxe-simbdl.vh-prelayout .splide__list {
display: flex;
}
#brxe-simbdl.vh-prelayout .splide__slide {
margin-right: var(--vh-gap, 1.3vw);
min-height: var(--vh-minh, 36rem);
}
</style>
<script>
(function(){
const SPLIDE_ROOT_ID = 'brxe-simbdl'; // <-- schimbi pt instanța 2
const FILTER_SELECT_ID = 'brxe-zuequz'; // <-- schimbi pt instanța 2
const PRICE_ANIMATIONS = false;
const HOVER_PREFETCH = true;
function onReady(fn){
if(document.readyState==='loading'){
document.addEventListener('DOMContentLoaded', fn,{once:true});
} else {
fn();
}
}
function getApiRoot(){
return (window.wpApiSettings && window.wpApiSettings.root) || '/wp-json/';
}
async function fetchVariationData(variationId, decimals){
const url = getApiRoot() + 'my/v1/variation-discount/' + encodeURIComponent(variationId) + '?decimals=' + (decimals ?? 0);
const res = await fetch(url, { credentials:'same-origin' });
if(!res.ok) throw new Error('HTTP '+res.status);
return res.json();
}
const forEach = (nl, cb)=> Array.prototype.forEach.call(nl, cb);
const isClone = el => !!el.closest('.splide__slide--clone');
function ensureShown(el){
if(el && getComputedStyle(el).display==='none'){
el.style.setProperty('display','flex','important');
}
}
function nfRON(val){
if(val==null||val==='') return '';
const n=Number(val);
if(!Number.isFinite(n)) return '';
return new Intl.NumberFormat('ro-RO',{minimumFractionDigits:0,maximumFractionDigits:2}).format(n)+' RON';
}
function stockTextRo(s){
return s==='instock'?'În stoc'
:s==='outofstock'?'Stoc epuizat'
:s==='onbackorder'?'În stoc furnizor'
:'';
}
function stockColor(s){
return s==='instock' ?'#00E832'
:s==='outofstock' ?'#FF0000'
:s==='onbackorder' ?'#ffb22e'
:'#9ca3af';
}
function formatDim(v,u){
if(v==null||v==='') return '';
return `${v}${u||''}`.trim();
}
function getFullUrlFromItem(item){
if(!item) return '';
const d=item.getAttribute('data-url'); if(d) return d;
const a=item.querySelector('a[href]'); if(a&&a.href) return a.href;
const img=item.querySelector('img'); if(img) return img.currentSrc||img.src||'';
return '';
}
const _barTimers=new WeakMap(), _hideTimers=new WeakMap();
function cancelOldBar(el){
const t=_barTimers.get(el);
if(t){clearTimeout(t);_barTimers.delete(el);}
}
function animateOldPriceBar(barEl){
if (!PRICE_ANIMATIONS || !barEl) return;
const t = barEl.style.transition;
if (!t || !/min-width/.test(t)){
barEl.style.transition = 'min-width .2s ease-in-out';
}
barEl.style.minWidth = '0%';
void barEl.offsetWidth;
barEl.style.minWidth = '110%';
}
function scheduleOldBar(el){
if(!PRICE_ANIMATIONS) return;
cancelOldBar(el);
const t=setTimeout(()=>{
animateOldPriceBar(el);
_barTimers.delete(el);
}, 0);
_barTimers.set(el,t);
}
function _scheduleHide(el,ms){
if(!PRICE_ANIMATIONS){
el.style.opacity=0;
return;
}
if(!el) return;
_cancelHide(el);
const t=setTimeout(()=>{
el.style.opacity=0;
_hideTimers.delete(el);
},ms);
_hideTimers.set(el,t);
}
function _cancelHide(el){
const t=_hideTimers.get(el);
if(t){clearTimeout(t);_hideTimers.delete(el);}
}
function hideOldPrice(el,delay){
if(!el) return;
if(PRICE_ANIMATIONS && delay>0){
_scheduleHide(el,delay);
} else {
_cancelHide(el);
el.style.opacity=0;
}
}
function showOldPrice(el){
if(!el) return;
_cancelHide(el);
ensureShown(el);
el.style.opacity=1;
}
function updateDiscountBox(card,p){
const box=card.querySelector('.reducere-produs-shop');
const text=card.querySelector('.text-reducere-produs-shop');
if(!box||!text) return;
if(!p||p.discount_percent==null){
box.style.opacity=0;
return;
}
const v='-'+p.discount_percent+'%';
if(text.textContent!==v) text.textContent=v;
ensureShown(box);
box.style.opacity=1;
}
function updateStockBox(card,p){
const wrap=card.querySelector('.stoc-produs-shop');
const dot=card.querySelector('.punct-stoc-produs-shop');
const txt=card.querySelector('.text-stoc-produs-shop');
if(!wrap||!dot||!txt) return;
const status=p&&p.stock_status?String(p.stock_status):'';
const label=stockTextRo(status);
if(!label){
wrap.classList.remove('is-visible');
if(txt.textContent) txt.textContent='';
return;
}
if(txt.textContent!==label) txt.textContent=label;
const c=stockColor(status);
if(dot.style.backgroundColor!==c) dot.style.backgroundColor=c;
ensureShown(wrap);
wrap.classList.add('is-visible');
}
function updateDimensions(card,p){
const l=card.querySelector('.text-lungime-produs-shop');
const w=card.querySelector('.text-adancime-produs-shop');
const h=card.querySelector('.text-inaltime-produs-shop');
if(!l && !w && !h) return;
const unit=p&&p.dimension_unit?String(p.dimension_unit):'';
const L=p?p.length:null, W=p?p.width:null, H=p?p.height:null;
if(l){ const v=formatDim(L,unit); if(l.textContent!==v) l.textContent=v; }
if(w){ const v=formatDim(W,unit); if(w.textContent!==v) w.textContent=v; }
if(h){ const v=formatDim(H,unit); if(h.textContent!==v) h.textContent=v; }
}
function updatePrices(card,p){
const actual=card.querySelector('.pret-actual-produs-shop');
const oldWrap=card.querySelector('.wrap-pret-vechi-produs-shop');
const oldText=card.querySelector('.pret-vechi-produs-shop');
const oldBar =card.querySelector('.div-pret-vechi-produs-shop');
if(!actual) return;
const reg = p && p.regular_price!=null ? p.regular_price : null;
const sale= p && p.sale_price !=null ? p.sale_price : null;
// niciun preț valid
if(reg==null && sale==null){
if(actual.textContent) actual.textContent='';
if(oldWrap) hideOldPrice(oldWrap,0);
if(oldBar){
cancelOldBar(oldBar);
oldBar.style.minWidth='0%';
}
if(oldText&&oldText.textContent) oldText.textContent='';
return;
}
// există reducere reală
if(sale!=null && reg!=null && +sale>0 && +reg>0 && +sale<+reg){
const cur=nfRON(sale);
if(actual.textContent!==cur) actual.textContent=cur;
if(oldWrap) showOldPrice(oldWrap);
const regTxt=nfRON(reg);
if(oldText && oldText.textContent!==regTxt) oldText.textContent=regTxt;
if(oldBar){
cancelOldBar(oldBar);
if (PRICE_ANIMATIONS) {
scheduleOldBar(oldBar);
} else {
// fără animații -> fă bara vizibilă din nou
oldBar.style.minWidth = '110%';
}
}
return;
}
// fără reducere -> afișăm doar prețul normal și ascundem bara veche
const cur=nfRON(reg!=null?reg:sale);
if(actual.textContent!==cur) actual.textContent=cur;
if(oldBar){
cancelOldBar(oldBar);
oldBar.style.minWidth='0%';
}
if(oldWrap){
hideOldPrice(oldWrap, PRICE_ANIMATIONS ? 200 : 0);
}
}
function setMainImage(card, url){
const main=card.querySelector('[data-main-image]');
if(!main||!url) return;
if(main.dataset.mainSrc===url) return;
const pre=new Image();
pre.onload=function(){
if(main.dataset.mainSrc===url) return;
if(main.tagName==='IMG'){
main.setAttribute('src',url);
} else {
main.style.backgroundImage='url("'+url+'")';
}
main.dataset.mainSrc=url;
};
pre.src=url;
}
function setActiveItem(card, active){
forEach(card.querySelectorAll('[data-variation-item]'), el=>{
const act=el===active;
el.classList.toggle('is-active',act);
el.setAttribute('aria-selected', act?'true':'false');
});
}
const variationCache=new Map();
const prefetchQueue=new Set();
async function prefetchIds(ids){
const tasks=[];
ids.forEach(id=>{
if(!id) return;
if(!variationCache.has(id) && !prefetchQueue.has(id)){
prefetchQueue.add(id);
tasks.push(
fetchVariationData(id,0)
.then(d=>variationCache.set(id,d))
.catch(()=>variationCache.set(id,null))
.finally(()=>prefetchQueue.delete(id))
);
}
});
if(tasks.length) await Promise.allSettled(tasks);
}
async function prefetchAllIn(container){
const ids=new Set(
Array.from(container.querySelectorAll('[data-variation-item][data-variation-id]'))
.filter(el=>!isClone(el))
.map(el=>el.getAttribute('data-variation-id'))
.filter(Boolean)
);
await prefetchIds(ids);
}
async function initCard(card){
if(!card || card.dataset.init==='1') return;
if(isClone(card)) return;
card.dataset.init='1';
const firstItem=card.querySelector('[data-variation-item][data-variation-id]');
if(!firstItem) return;
setActiveItem(card, firstItem);
const vid=firstItem.getAttribute('data-variation-id');
const cached=variationCache.get(vid);
if(cached!==undefined){
updateDiscountBox(card,cached);
updateStockBox(card,cached);
updateDimensions(card,cached);
updatePrices(card,cached);
} else {
try{
const data=await fetchVariationData(vid,0);
variationCache.set(vid,data);
updateDiscountBox(card,data);
updateStockBox(card,data);
updateDimensions(card,data);
updatePrices(card,data);
}catch(e){
variationCache.set(vid, null);
}
}
const firstUrl=getFullUrlFromItem(firstItem);
if(firstUrl) setMainImage(card, firstUrl);
}
function initAllCards(root){
forEach((root||document).querySelectorAll('[data-product-card]'), card=>initCard(card));
}
// ==== SPLIDE MANAGER PER INSTANȚĂ ====
let ownSplide=null;
let rebuilding=false;
function getRoot(){
return document.getElementById(SPLIDE_ROOT_ID);
}
function readBricksOptions(rootEl){
try{
const raw=rootEl.getAttribute('data-splide');
if(!raw) return {};
const opts=JSON.parse(raw);
return Object.assign({ type:'slide', speed:400, perPage:4, gap:'1.3vw', autoHeight:false }, opts);
}catch(e){
return { type:'slide', gap:'1.3vw', autoHeight:false };
}
}
function detachBricksInstance(rootEl){
if(!rootEl) return;
const map = (window.bricksData && window.bricksData.splideInstances) || null;
if(map){
for(const k of Object.keys(map)){
const inst = map[k];
if(inst && (inst.root===rootEl || inst.root?.id===rootEl.id)){
try{ inst.destroy && inst.destroy(true); }catch(e){}
map[k]=null;
}
}
}
if(!rootEl.dataset.vh_splide_opts){
const opts = readBricksOptions(rootEl);
rootEl.dataset.vh_splide_opts = JSON.stringify(opts);
}
rootEl.removeAttribute('data-splide');
rootEl.classList.add('vh-splide-locked');
}
function resetInline(rootEl){
const track=rootEl.querySelector('.splide__track');
const list =rootEl.querySelector('.splide__list');
const slides=rootEl.querySelectorAll('.splide__slide');
if(track){ track.style.height=''; track.style.transform=''; }
if(list ){ list.style.height=''; list.style.transform=''; list.style.gap=''; }
slides.forEach(sl=>{
sl.style.height='';
sl.style.minHeight='';
sl.style.margin='';
});
}
function ensureStructure(rootEl){
let track = rootEl.querySelector('.splide__track');
let list = rootEl.querySelector('.splide__list');
if(!track){
track = document.createElement('div');
track.className='splide__track';
while(rootEl.firstChild) track.appendChild(rootEl.firstChild);
rootEl.appendChild(track);
}
if(!list){
list = document.createElement('ul');
list.className='splide__list';
const children = Array.from(track.children);
children.forEach(ch=>{
const li=document.createElement('li');
li.className='splide__slide';
li.appendChild(ch);
list.appendChild(li);
});
track.innerHTML='';
track.appendChild(list);
}
const kids = Array.from(list.children);
kids.forEach(li=>{
if(!li.classList.contains('splide__slide')){
li.classList.add('splide__slide');
}
});
list.querySelectorAll('.splide__slide--clone').forEach(c=>c.remove());
return {track, list};
}
function lockVisual(rootEl){
if (!rootEl) return;
const opts = (()=>{
try{ return JSON.parse(rootEl.dataset.vh_splide_opts || '{}'); } catch(e){ return {}; }
})();
rootEl.style.setProperty('--vh-gap', (opts.gap || '1.3vw'));
if (opts.fixedHeight) rootEl.style.setProperty('--vh-minh', opts.fixedHeight);
// ascundem până terminăm rebuild-ul
rootEl.style.setProperty('opacity', '0', 'important');
rootEl.style.setProperty('visibility', 'hidden', 'important');
rootEl.style.setProperty('pointer-events', 'none', 'important');
rootEl.classList.add('vh-prelayout','vh-mask');
}
function unlockVisual(rootEl){
if (!rootEl) return;
rootEl.style.removeProperty('opacity');
rootEl.style.removeProperty('visibility');
rootEl.style.removeProperty('pointer-events');
rootEl.classList.remove('vh-mask','vh-prelayout');
}
async function buildSplide(){
const rootEl=getRoot();
if(!rootEl || !window.Splide) return;
if(rebuilding) return;
rebuilding = true;
lockVisual(rootEl);
detachBricksInstance(rootEl);
resetInline(rootEl);
ensureStructure(rootEl);
const opts = (()=>{
try{ return JSON.parse(rootEl.dataset.vh_splide_opts || '{}'); } catch(e){ return {}; }
})();
if(ownSplide){
try{ ownSplide.destroy(true); }catch(e){}
ownSplide=null;
}
ownSplide = new Splide(rootEl, opts);
ownSplide.mount();
// stabilizare într-un frame înainte să-l arătăm
await new Promise(r=>requestAnimationFrame(()=>r()));
ownSplide.refresh();
ownSplide.emit && ownSplide.emit('resize');
unlockVisual(rootEl);
if(!window.bricksData) window.bricksData = {};
if(!window.bricksData.splideInstances) window.bricksData.splideInstances = {};
window.bricksData.splideInstances[SPLIDE_ROOT_ID + '__own'] = ownSplide;
rebuilding = false;
}
// debounce rebuild cu token, ca să nu dăm rebuild de 2 ori
let rebuildToken = 0;
let rebuildTimerRef = null;
function rebuildSplideDebounced(delay=100){
const myToken = ++rebuildToken;
if(rebuildTimerRef) clearTimeout(rebuildTimerRef);
rebuildTimerRef = setTimeout(()=>{
if(myToken !== rebuildToken) return;
buildSplide();
}, delay);
}
// ====== Variation click (schimbă variantă + UI card) ======
function onClickVariation(e){
const item=e.target.closest && e.target.closest('[data-variation-item][data-variation-id]');
if(!item) return;
const a=e.target.closest('a');
if(a && item.contains(a)) e.preventDefault();
const card=item.closest('[data-product-card]');
if(!card || isClone(card)) return;
const vid=item.getAttribute('data-variation-id');
setActiveItem(card,item);
const data=variationCache.get(vid);
if(data!==undefined){
updateDiscountBox(card,data);
updateStockBox(card,data);
updateDimensions(card,data);
updatePrices(card,data);
} else {
fetchVariationData(vid,0).then(d=>{
variationCache.set(vid,d);
updateDiscountBox(card,d);
updateStockBox(card,d);
updateDimensions(card,d);
updatePrices(card,d);
}).catch(()=>{
variationCache.set(vid,null);
});
// prefetch pentru restul variantelor din același card
const siblings = Array.from(
card.querySelectorAll('[data-variation-item][data-variation-id]')
).map(el=>el.getAttribute('data-variation-id'));
prefetchIds(new Set(siblings));
}
const fullUrl=getFullUrlFromItem(item);
if(fullUrl) setMainImage(card, fullUrl);
}
function attachHoverPrefetch(){
if(!HOVER_PREFETCH) return;
if(document.body.dataset.vhHoverBound==='1') return;
document.body.dataset.vhHoverBound='1';
document.addEventListener('mouseenter', e=>{
const it = e.target.closest && e.target.closest('[data-variation-item][data-variation-id]');
if(!it) return;
const vid = it.getAttribute('data-variation-id');
if(vid && !variationCache.has(vid)){
prefetchIds(new Set([vid]));
}
}, true);
}
// ====== Filter & observer ======
// stare doar pt sliderul ăsta
let awaitingDom = false;
let awaitingFallback= null;
let mo = null;
function attachFilterWatcher(){
const sel=document.getElementById(FILTER_SELECT_ID);
if(!sel || sel.dataset.vhBound==='1') return;
sel.dataset.vhBound='1';
sel.addEventListener('change', ()=>{
const rootEl=getRoot();
if(rootEl) lockVisual(rootEl); // ascundem sliderul vechi instant
awaitingDom = true; // așteptăm noul DOM după filtrare
// fallback dacă Bricks reordonează fără să schimbe nodurile într-un mod care declanșează observerul
if(awaitingFallback) clearTimeout(awaitingFallback);
awaitingFallback = setTimeout(()=>{
if(awaitingDom){
awaitingDom = false;
rebuildSplideDebounced(0);
}
}, 900);
// refacem cardurile după ce Bricks a actualizat conținutul intern
setTimeout(async ()=>{
const root=getRoot();
if(root){
const cont = root.querySelector('.splide__list') || root;
await prefetchAllIn(cont);
initAllCards(document);
}
}, 30);
});
}
function startObserver(){
if(mo) return;
mo=new MutationObserver((mut)=>{
const rootEl = getRoot();
if(!rootEl) return;
let touch = false;
let addedRoot = null;
for(const m of mut){
if(m.type!=='childList') continue;
// verificăm DOAR mutații care ating sliderul ăsta
m.addedNodes && m.addedNodes.forEach(n=>{
if(n.nodeType!==1) return;
// 1) dacă nodul adăugat ESTE chiar root-ul meu
if(n === rootEl){
touch=true;
addedRoot=rootEl;
return;
}
// 2) dacă nodul adăugat CONȚINE root-ul meu
if(n.contains && n.contains(rootEl)){
touch=true;
addedRoot=rootEl;
return;
}
// 3) dacă root-ul meu conține nodul adăugat (s-a schimbat conținutul intern al sliderului meu)
if(rootEl.contains(n)){
touch=true;
addedRoot=rootEl;
return;
}
});
}
if(!touch) return; // ignora mutațiile altor slider-e
// Am detectat modificare relevantă PENTRU sliderul acesta
const activeRoot = addedRoot || rootEl;
if(activeRoot) lockVisual(activeRoot); // îl ascundem până terminăm rebuild
if(awaitingDom){
// era un refresh de filtrare pentru sliderul ăsta
awaitingDom = false;
if(awaitingFallback){
clearTimeout(awaitingFallback);
awaitingFallback=null;
}
rebuildSplideDebounced(60); // rebuild rapid pt sliderul ăsta
} else {
// doar o mică mutație (ex. resize/reflow etc.)
rebuildSplideDebounced(100);
}
// re-init la carduri după ce DOM-ul nou e acolo
setTimeout(()=>initAllCards(document), 20);
});
// Observăm tot body-ul, dar în callback filtrăm strict pe root-ul ăsta
mo.observe(document.body,{childList:true,subtree:true});
}
// ====== ENTRY POINT ======
onReady(async function(){
const root0 = getRoot();
if (root0) await prefetchAllIn(root0);
initAllCards(document);
if(!document.body.dataset.vhClickBound){
document.addEventListener('click', onClickVariation);
document.body.dataset.vhClickBound='1';
}
attachHoverPrefetch();
attachFilterWatcher();
startObserver();
if(root0){
const opts = readBricksOptions(root0);
root0.style.setProperty('--vh-gap', (opts.gap || '1.3vw'));
if (opts.fixedHeight) root0.style.setProperty('--vh-minh', opts.fixedHeight);
}
buildSplide();
window.addEventListener('resize', ()=>{
rebuildSplideDebounced(100);
}, {passive:true});
});
})();
</script>
asf
L
90cm
I
90cm
A
90cm
976 RON
976 RON
Aplică codul SPEED20 pentru -20% reducere
<style>
/* Ascunde complet sliderul PÂNĂ e 100% montat (fără fade/blink) */
#brxe-simbdl.vh-mask {
opacity: 0 !important;
visibility: hidden !important;
pointer-events: none !important;
}
/* Prelayout: imităm EXACT ce va face Splide după mount,
ca să nu existe schimbare vizuală la gap/înălțime */
#brxe-simbdl.vh-prelayout .splide__list {
display: flex;
}
#brxe-simbdl.vh-prelayout .splide__slide {
margin-right: var(--vh-gap, 1.3vw);
min-height: var(--vh-minh, 36rem);
}
</style>
<script>
(function(){
const SPLIDE_ROOT_ID = 'brxe-simbdl'; // <-- schimbi pt instanța 2
const FILTER_SELECT_ID = 'brxe-zuequz'; // <-- schimbi pt instanța 2
const PRICE_ANIMATIONS = false;
const HOVER_PREFETCH = true;
function onReady(fn){
if(document.readyState==='loading'){
document.addEventListener('DOMContentLoaded', fn,{once:true});
} else {
fn();
}
}
function getApiRoot(){
return (window.wpApiSettings && window.wpApiSettings.root) || '/wp-json/';
}
async function fetchVariationData(variationId, decimals){
const url = getApiRoot() + 'my/v1/variation-discount/' + encodeURIComponent(variationId) + '?decimals=' + (decimals ?? 0);
const res = await fetch(url, { credentials:'same-origin' });
if(!res.ok) throw new Error('HTTP '+res.status);
return res.json();
}
const forEach = (nl, cb)=> Array.prototype.forEach.call(nl, cb);
const isClone = el => !!el.closest('.splide__slide--clone');
function ensureShown(el){
if(el && getComputedStyle(el).display==='none'){
el.style.setProperty('display','flex','important');
}
}
function nfRON(val){
if(val==null||val==='') return '';
const n=Number(val);
if(!Number.isFinite(n)) return '';
return new Intl.NumberFormat('ro-RO',{minimumFractionDigits:0,maximumFractionDigits:2}).format(n)+' RON';
}
function stockTextRo(s){
return s==='instock'?'În stoc'
:s==='outofstock'?'Stoc epuizat'
:s==='onbackorder'?'În stoc furnizor'
:'';
}
function stockColor(s){
return s==='instock' ?'#00E832'
:s==='outofstock' ?'#FF0000'
:s==='onbackorder' ?'#ffb22e'
:'#9ca3af';
}
function formatDim(v,u){
if(v==null||v==='') return '';
return `${v}${u||''}`.trim();
}
function getFullUrlFromItem(item){
if(!item) return '';
const d=item.getAttribute('data-url'); if(d) return d;
const a=item.querySelector('a[href]'); if(a&&a.href) return a.href;
const img=item.querySelector('img'); if(img) return img.currentSrc||img.src||'';
return '';
}
const _barTimers=new WeakMap(), _hideTimers=new WeakMap();
function cancelOldBar(el){
const t=_barTimers.get(el);
if(t){clearTimeout(t);_barTimers.delete(el);}
}
function animateOldPriceBar(barEl){
if (!PRICE_ANIMATIONS || !barEl) return;
const t = barEl.style.transition;
if (!t || !/min-width/.test(t)){
barEl.style.transition = 'min-width .2s ease-in-out';
}
barEl.style.minWidth = '0%';
void barEl.offsetWidth;
barEl.style.minWidth = '110%';
}
function scheduleOldBar(el){
if(!PRICE_ANIMATIONS) return;
cancelOldBar(el);
const t=setTimeout(()=>{
animateOldPriceBar(el);
_barTimers.delete(el);
}, 0);
_barTimers.set(el,t);
}
function _scheduleHide(el,ms){
if(!PRICE_ANIMATIONS){
el.style.opacity=0;
return;
}
if(!el) return;
_cancelHide(el);
const t=setTimeout(()=>{
el.style.opacity=0;
_hideTimers.delete(el);
},ms);
_hideTimers.set(el,t);
}
function _cancelHide(el){
const t=_hideTimers.get(el);
if(t){clearTimeout(t);_hideTimers.delete(el);}
}
function hideOldPrice(el,delay){
if(!el) return;
if(PRICE_ANIMATIONS && delay>0){
_scheduleHide(el,delay);
} else {
_cancelHide(el);
el.style.opacity=0;
}
}
function showOldPrice(el){
if(!el) return;
_cancelHide(el);
ensureShown(el);
el.style.opacity=1;
}
function updateDiscountBox(card,p){
const box=card.querySelector('.reducere-produs-shop');
const text=card.querySelector('.text-reducere-produs-shop');
if(!box||!text) return;
if(!p||p.discount_percent==null){
box.style.opacity=0;
return;
}
const v='-'+p.discount_percent+'%';
if(text.textContent!==v) text.textContent=v;
ensureShown(box);
box.style.opacity=1;
}
function updateStockBox(card,p){
const wrap=card.querySelector('.stoc-produs-shop');
const dot=card.querySelector('.punct-stoc-produs-shop');
const txt=card.querySelector('.text-stoc-produs-shop');
if(!wrap||!dot||!txt) return;
const status=p&&p.stock_status?String(p.stock_status):'';
const label=stockTextRo(status);
if(!label){
wrap.classList.remove('is-visible');
if(txt.textContent) txt.textContent='';
return;
}
if(txt.textContent!==label) txt.textContent=label;
const c=stockColor(status);
if(dot.style.backgroundColor!==c) dot.style.backgroundColor=c;
ensureShown(wrap);
wrap.classList.add('is-visible');
}
function updateDimensions(card,p){
const l=card.querySelector('.text-lungime-produs-shop');
const w=card.querySelector('.text-adancime-produs-shop');
const h=card.querySelector('.text-inaltime-produs-shop');
if(!l && !w && !h) return;
const unit=p&&p.dimension_unit?String(p.dimension_unit):'';
const L=p?p.length:null, W=p?p.width:null, H=p?p.height:null;
if(l){ const v=formatDim(L,unit); if(l.textContent!==v) l.textContent=v; }
if(w){ const v=formatDim(W,unit); if(w.textContent!==v) w.textContent=v; }
if(h){ const v=formatDim(H,unit); if(h.textContent!==v) h.textContent=v; }
}
function updatePrices(card,p){
const actual=card.querySelector('.pret-actual-produs-shop');
const oldWrap=card.querySelector('.wrap-pret-vechi-produs-shop');
const oldText=card.querySelector('.pret-vechi-produs-shop');
const oldBar =card.querySelector('.div-pret-vechi-produs-shop');
if(!actual) return;
const reg = p && p.regular_price!=null ? p.regular_price : null;
const sale= p && p.sale_price !=null ? p.sale_price : null;
// niciun preț valid
if(reg==null && sale==null){
if(actual.textContent) actual.textContent='';
if(oldWrap) hideOldPrice(oldWrap,0);
if(oldBar){
cancelOldBar(oldBar);
oldBar.style.minWidth='0%';
}
if(oldText&&oldText.textContent) oldText.textContent='';
return;
}
// există reducere reală
if(sale!=null && reg!=null && +sale>0 && +reg>0 && +sale<+reg){
const cur=nfRON(sale);
if(actual.textContent!==cur) actual.textContent=cur;
if(oldWrap) showOldPrice(oldWrap);
const regTxt=nfRON(reg);
if(oldText && oldText.textContent!==regTxt) oldText.textContent=regTxt;
if(oldBar){
cancelOldBar(oldBar);
if (PRICE_ANIMATIONS) {
scheduleOldBar(oldBar);
} else {
// fără animații -> fă bara vizibilă din nou
oldBar.style.minWidth = '110%';
}
}
return;
}
// fără reducere -> afișăm doar prețul normal și ascundem bara veche
const cur=nfRON(reg!=null?reg:sale);
if(actual.textContent!==cur) actual.textContent=cur;
if(oldBar){
cancelOldBar(oldBar);
oldBar.style.minWidth='0%';
}
if(oldWrap){
hideOldPrice(oldWrap, PRICE_ANIMATIONS ? 200 : 0);
}
}
function setMainImage(card, url){
const main=card.querySelector('[data-main-image]');
if(!main||!url) return;
if(main.dataset.mainSrc===url) return;
const pre=new Image();
pre.onload=function(){
if(main.dataset.mainSrc===url) return;
if(main.tagName==='IMG'){
main.setAttribute('src',url);
} else {
main.style.backgroundImage='url("'+url+'")';
}
main.dataset.mainSrc=url;
};
pre.src=url;
}
function setActiveItem(card, active){
forEach(card.querySelectorAll('[data-variation-item]'), el=>{
const act=el===active;
el.classList.toggle('is-active',act);
el.setAttribute('aria-selected', act?'true':'false');
});
}
const variationCache=new Map();
const prefetchQueue=new Set();
async function prefetchIds(ids){
const tasks=[];
ids.forEach(id=>{
if(!id) return;
if(!variationCache.has(id) && !prefetchQueue.has(id)){
prefetchQueue.add(id);
tasks.push(
fetchVariationData(id,0)
.then(d=>variationCache.set(id,d))
.catch(()=>variationCache.set(id,null))
.finally(()=>prefetchQueue.delete(id))
);
}
});
if(tasks.length) await Promise.allSettled(tasks);
}
async function prefetchAllIn(container){
const ids=new Set(
Array.from(container.querySelectorAll('[data-variation-item][data-variation-id]'))
.filter(el=>!isClone(el))
.map(el=>el.getAttribute('data-variation-id'))
.filter(Boolean)
);
await prefetchIds(ids);
}
async function initCard(card){
if(!card || card.dataset.init==='1') return;
if(isClone(card)) return;
card.dataset.init='1';
const firstItem=card.querySelector('[data-variation-item][data-variation-id]');
if(!firstItem) return;
setActiveItem(card, firstItem);
const vid=firstItem.getAttribute('data-variation-id');
const cached=variationCache.get(vid);
if(cached!==undefined){
updateDiscountBox(card,cached);
updateStockBox(card,cached);
updateDimensions(card,cached);
updatePrices(card,cached);
} else {
try{
const data=await fetchVariationData(vid,0);
variationCache.set(vid,data);
updateDiscountBox(card,data);
updateStockBox(card,data);
updateDimensions(card,data);
updatePrices(card,data);
}catch(e){
variationCache.set(vid, null);
}
}
const firstUrl=getFullUrlFromItem(firstItem);
if(firstUrl) setMainImage(card, firstUrl);
}
function initAllCards(root){
forEach((root||document).querySelectorAll('[data-product-card]'), card=>initCard(card));
}
// ==== SPLIDE MANAGER PER INSTANȚĂ ====
let ownSplide=null;
let rebuilding=false;
function getRoot(){
return document.getElementById(SPLIDE_ROOT_ID);
}
function readBricksOptions(rootEl){
try{
const raw=rootEl.getAttribute('data-splide');
if(!raw) return {};
const opts=JSON.parse(raw);
return Object.assign({ type:'slide', speed:400, perPage:4, gap:'1.3vw', autoHeight:false }, opts);
}catch(e){
return { type:'slide', gap:'1.3vw', autoHeight:false };
}
}
function detachBricksInstance(rootEl){
if(!rootEl) return;
const map = (window.bricksData && window.bricksData.splideInstances) || null;
if(map){
for(const k of Object.keys(map)){
const inst = map[k];
if(inst && (inst.root===rootEl || inst.root?.id===rootEl.id)){
try{ inst.destroy && inst.destroy(true); }catch(e){}
map[k]=null;
}
}
}
if(!rootEl.dataset.vh_splide_opts){
const opts = readBricksOptions(rootEl);
rootEl.dataset.vh_splide_opts = JSON.stringify(opts);
}
rootEl.removeAttribute('data-splide');
rootEl.classList.add('vh-splide-locked');
}
function resetInline(rootEl){
const track=rootEl.querySelector('.splide__track');
const list =rootEl.querySelector('.splide__list');
const slides=rootEl.querySelectorAll('.splide__slide');
if(track){ track.style.height=''; track.style.transform=''; }
if(list ){ list.style.height=''; list.style.transform=''; list.style.gap=''; }
slides.forEach(sl=>{
sl.style.height='';
sl.style.minHeight='';
sl.style.margin='';
});
}
function ensureStructure(rootEl){
let track = rootEl.querySelector('.splide__track');
let list = rootEl.querySelector('.splide__list');
if(!track){
track = document.createElement('div');
track.className='splide__track';
while(rootEl.firstChild) track.appendChild(rootEl.firstChild);
rootEl.appendChild(track);
}
if(!list){
list = document.createElement('ul');
list.className='splide__list';
const children = Array.from(track.children);
children.forEach(ch=>{
const li=document.createElement('li');
li.className='splide__slide';
li.appendChild(ch);
list.appendChild(li);
});
track.innerHTML='';
track.appendChild(list);
}
const kids = Array.from(list.children);
kids.forEach(li=>{
if(!li.classList.contains('splide__slide')){
li.classList.add('splide__slide');
}
});
list.querySelectorAll('.splide__slide--clone').forEach(c=>c.remove());
return {track, list};
}
function lockVisual(rootEl){
if (!rootEl) return;
const opts = (()=>{
try{ return JSON.parse(rootEl.dataset.vh_splide_opts || '{}'); } catch(e){ return {}; }
})();
rootEl.style.setProperty('--vh-gap', (opts.gap || '1.3vw'));
if (opts.fixedHeight) rootEl.style.setProperty('--vh-minh', opts.fixedHeight);
// ascundem până terminăm rebuild-ul
rootEl.style.setProperty('opacity', '0', 'important');
rootEl.style.setProperty('visibility', 'hidden', 'important');
rootEl.style.setProperty('pointer-events', 'none', 'important');
rootEl.classList.add('vh-prelayout','vh-mask');
}
function unlockVisual(rootEl){
if (!rootEl) return;
rootEl.style.removeProperty('opacity');
rootEl.style.removeProperty('visibility');
rootEl.style.removeProperty('pointer-events');
rootEl.classList.remove('vh-mask','vh-prelayout');
}
async function buildSplide(){
const rootEl=getRoot();
if(!rootEl || !window.Splide) return;
if(rebuilding) return;
rebuilding = true;
lockVisual(rootEl);
detachBricksInstance(rootEl);
resetInline(rootEl);
ensureStructure(rootEl);
const opts = (()=>{
try{ return JSON.parse(rootEl.dataset.vh_splide_opts || '{}'); } catch(e){ return {}; }
})();
if(ownSplide){
try{ ownSplide.destroy(true); }catch(e){}
ownSplide=null;
}
ownSplide = new Splide(rootEl, opts);
ownSplide.mount();
// stabilizare într-un frame înainte să-l arătăm
await new Promise(r=>requestAnimationFrame(()=>r()));
ownSplide.refresh();
ownSplide.emit && ownSplide.emit('resize');
unlockVisual(rootEl);
if(!window.bricksData) window.bricksData = {};
if(!window.bricksData.splideInstances) window.bricksData.splideInstances = {};
window.bricksData.splideInstances[SPLIDE_ROOT_ID + '__own'] = ownSplide;
rebuilding = false;
}
// debounce rebuild cu token, ca să nu dăm rebuild de 2 ori
let rebuildToken = 0;
let rebuildTimerRef = null;
function rebuildSplideDebounced(delay=100){
const myToken = ++rebuildToken;
if(rebuildTimerRef) clearTimeout(rebuildTimerRef);
rebuildTimerRef = setTimeout(()=>{
if(myToken !== rebuildToken) return;
buildSplide();
}, delay);
}
// ====== Variation click (schimbă variantă + UI card) ======
function onClickVariation(e){
const item=e.target.closest && e.target.closest('[data-variation-item][data-variation-id]');
if(!item) return;
const a=e.target.closest('a');
if(a && item.contains(a)) e.preventDefault();
const card=item.closest('[data-product-card]');
if(!card || isClone(card)) return;
const vid=item.getAttribute('data-variation-id');
setActiveItem(card,item);
const data=variationCache.get(vid);
if(data!==undefined){
updateDiscountBox(card,data);
updateStockBox(card,data);
updateDimensions(card,data);
updatePrices(card,data);
} else {
fetchVariationData(vid,0).then(d=>{
variationCache.set(vid,d);
updateDiscountBox(card,d);
updateStockBox(card,d);
updateDimensions(card,d);
updatePrices(card,d);
}).catch(()=>{
variationCache.set(vid,null);
});
// prefetch pentru restul variantelor din același card
const siblings = Array.from(
card.querySelectorAll('[data-variation-item][data-variation-id]')
).map(el=>el.getAttribute('data-variation-id'));
prefetchIds(new Set(siblings));
}
const fullUrl=getFullUrlFromItem(item);
if(fullUrl) setMainImage(card, fullUrl);
}
function attachHoverPrefetch(){
if(!HOVER_PREFETCH) return;
if(document.body.dataset.vhHoverBound==='1') return;
document.body.dataset.vhHoverBound='1';
document.addEventListener('mouseenter', e=>{
const it = e.target.closest && e.target.closest('[data-variation-item][data-variation-id]');
if(!it) return;
const vid = it.getAttribute('data-variation-id');
if(vid && !variationCache.has(vid)){
prefetchIds(new Set([vid]));
}
}, true);
}
// ====== Filter & observer ======
// stare doar pt sliderul ăsta
let awaitingDom = false;
let awaitingFallback= null;
let mo = null;
function attachFilterWatcher(){
const sel=document.getElementById(FILTER_SELECT_ID);
if(!sel || sel.dataset.vhBound==='1') return;
sel.dataset.vhBound='1';
sel.addEventListener('change', ()=>{
const rootEl=getRoot();
if(rootEl) lockVisual(rootEl); // ascundem sliderul vechi instant
awaitingDom = true; // așteptăm noul DOM după filtrare
// fallback dacă Bricks reordonează fără să schimbe nodurile într-un mod care declanșează observerul
if(awaitingFallback) clearTimeout(awaitingFallback);
awaitingFallback = setTimeout(()=>{
if(awaitingDom){
awaitingDom = false;
rebuildSplideDebounced(0);
}
}, 900);
// refacem cardurile după ce Bricks a actualizat conținutul intern
setTimeout(async ()=>{
const root=getRoot();
if(root){
const cont = root.querySelector('.splide__list') || root;
await prefetchAllIn(cont);
initAllCards(document);
}
}, 30);
});
}
function startObserver(){
if(mo) return;
mo=new MutationObserver((mut)=>{
const rootEl = getRoot();
if(!rootEl) return;
let touch = false;
let addedRoot = null;
for(const m of mut){
if(m.type!=='childList') continue;
// verificăm DOAR mutații care ating sliderul ăsta
m.addedNodes && m.addedNodes.forEach(n=>{
if(n.nodeType!==1) return;
// 1) dacă nodul adăugat ESTE chiar root-ul meu
if(n === rootEl){
touch=true;
addedRoot=rootEl;
return;
}
// 2) dacă nodul adăugat CONȚINE root-ul meu
if(n.contains && n.contains(rootEl)){
touch=true;
addedRoot=rootEl;
return;
}
// 3) dacă root-ul meu conține nodul adăugat (s-a schimbat conținutul intern al sliderului meu)
if(rootEl.contains(n)){
touch=true;
addedRoot=rootEl;
return;
}
});
}
if(!touch) return; // ignora mutațiile altor slider-e
// Am detectat modificare relevantă PENTRU sliderul acesta
const activeRoot = addedRoot || rootEl;
if(activeRoot) lockVisual(activeRoot); // îl ascundem până terminăm rebuild
if(awaitingDom){
// era un refresh de filtrare pentru sliderul ăsta
awaitingDom = false;
if(awaitingFallback){
clearTimeout(awaitingFallback);
awaitingFallback=null;
}
rebuildSplideDebounced(60); // rebuild rapid pt sliderul ăsta
} else {
// doar o mică mutație (ex. resize/reflow etc.)
rebuildSplideDebounced(100);
}
// re-init la carduri după ce DOM-ul nou e acolo
setTimeout(()=>initAllCards(document), 20);
});
// Observăm tot body-ul, dar în callback filtrăm strict pe root-ul ăsta
mo.observe(document.body,{childList:true,subtree:true});
}
// ====== ENTRY POINT ======
onReady(async function(){
const root0 = getRoot();
if (root0) await prefetchAllIn(root0);
initAllCards(document);
if(!document.body.dataset.vhClickBound){
document.addEventListener('click', onClickVariation);
document.body.dataset.vhClickBound='1';
}
attachHoverPrefetch();
attachFilterWatcher();
startObserver();
if(root0){
const opts = readBricksOptions(root0);
root0.style.setProperty('--vh-gap', (opts.gap || '1.3vw'));
if (opts.fixedHeight) root0.style.setProperty('--vh-minh', opts.fixedHeight);
}
buildSplide();
window.addEventListener('resize', ()=>{
rebuildSplideDebounced(100);
}, {passive:true});
});
})();
</script>
asf
L
90cm
I
90cm
A
90cm
976 RON
976 RON
Categorii Mobilier
Bucură-te de ofertele noastre
Mobilier dormitor
Paturi tapițate
•
Noptiere
•
Comode
Dressinguri
•
Alta Subcategorie
Mobilier dormitor
Paturi tapițate
•
Noptiere
•
Comode
Dressinguri
•
Alta Subcategorie
Mobilier dormitor
Paturi tapițate
•
Noptiere
•
Comode
Dressinguri
•
Alta Subcategorie
Mobilier dormitor
Paturi tapițate
•
Noptiere
•
Comode
Dressinguri
•
Alta Subcategorie
Mobilier dormitor
Paturi tapițate
•
Noptiere
•
Comode
Dressinguri
•
Alta Subcategorie
DE LA CASĂ LA ACASĂ
Prima platforma online design interior din Romania
Effortlessly transition from ideation to final product to increase productivity.
De la concept
la realitate
Consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation.
De la concept
la realitate
Consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation.
De la concept
la realitate
Consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation.
De la concept
la realitate
Consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation.
De la concept
la realitate
Consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation.
În stoc
Dulap maro/negru din lemn Nairobi Dutchbone
În stoc
Dulap maro/negru din lemn Nairobi Dutchbone
În stoc
Dulap maro/negru din lemn Nairobi Dutchbone
În stoc
Dulap maro/negru din lemn Nairobi Dutchbone
În stoc
Dulap maro/negru din lemn Nairobi Dutchbone
În stoc
Dulap maro/negru din lemn Nairobi Dutchbone
Produse Populare
Aplică codul SPEED20 pentru -20% reducere
<style>
/* Ascunde complet sliderul PÂNĂ e 100% montat (fără fade/blink) */
#brxe-akucji.vh-mask {
opacity: 0 !important;
visibility: hidden !important;
pointer-events: none !important;
}
/* Prelayout: imităm EXACT ce va face Splide după mount,
ca să nu existe schimbare vizuală la gap/înălțime */
#brxe-akucji.vh-prelayout .splide__list {
display: flex;
}
#brxe-akucji.vh-prelayout .splide__slide {
margin-right: var(--vh-gap, 1.3vw);
min-height: var(--vh-minh, 36rem);
}
</style>
<script>
(function(){
const SPLIDE_ROOT_ID = 'brxe-akucji'; // <-- schimbi pt instanța 2
const FILTER_SELECT_ID = 'brxe-dsvvdo'; // <-- schimbi pt instanța 2
const PRICE_ANIMATIONS = false;
const HOVER_PREFETCH = true;
function onReady(fn){
if(document.readyState==='loading'){
document.addEventListener('DOMContentLoaded', fn,{once:true});
} else {
fn();
}
}
function getApiRoot(){
return (window.wpApiSettings && window.wpApiSettings.root) || '/wp-json/';
}
async function fetchVariationData(variationId, decimals){
const url = getApiRoot() + 'my/v1/variation-discount/' + encodeURIComponent(variationId) + '?decimals=' + (decimals ?? 0);
const res = await fetch(url, { credentials:'same-origin' });
if(!res.ok) throw new Error('HTTP '+res.status);
return res.json();
}
const forEach = (nl, cb)=> Array.prototype.forEach.call(nl, cb);
const isClone = el => !!el.closest('.splide__slide--clone');
function ensureShown(el){
if(el && getComputedStyle(el).display==='none'){
el.style.setProperty('display','flex','important');
}
}
function nfRON(val){
if(val==null||val==='') return '';
const n=Number(val);
if(!Number.isFinite(n)) return '';
return new Intl.NumberFormat('ro-RO',{minimumFractionDigits:0,maximumFractionDigits:2}).format(n)+' RON';
}
function stockTextRo(s){
return s==='instock'?'În stoc'
:s==='outofstock'?'Stoc epuizat'
:s==='onbackorder'?'În stoc furnizor'
:'';
}
function stockColor(s){
return s==='instock' ?'#00E832'
:s==='outofstock' ?'#FF0000'
:s==='onbackorder' ?'#ffb22e'
:'#9ca3af';
}
function formatDim(v,u){
if(v==null||v==='') return '';
return `${v}${u||''}`.trim();
}
function getFullUrlFromItem(item){
if(!item) return '';
const d=item.getAttribute('data-url'); if(d) return d;
const a=item.querySelector('a[href]'); if(a&&a.href) return a.href;
const img=item.querySelector('img'); if(img) return img.currentSrc||img.src||'';
return '';
}
const _barTimers=new WeakMap(), _hideTimers=new WeakMap();
function cancelOldBar(el){
const t=_barTimers.get(el);
if(t){clearTimeout(t);_barTimers.delete(el);}
}
function animateOldPriceBar(barEl){
if (!PRICE_ANIMATIONS || !barEl) return;
const t = barEl.style.transition;
if (!t || !/min-width/.test(t)){
barEl.style.transition = 'min-width .2s ease-in-out';
}
barEl.style.minWidth = '0%';
void barEl.offsetWidth;
barEl.style.minWidth = '110%';
}
function scheduleOldBar(el){
if(!PRICE_ANIMATIONS) return;
cancelOldBar(el);
const t=setTimeout(()=>{
animateOldPriceBar(el);
_barTimers.delete(el);
}, 0);
_barTimers.set(el,t);
}
function _scheduleHide(el,ms){
if(!PRICE_ANIMATIONS){
el.style.opacity=0;
return;
}
if(!el) return;
_cancelHide(el);
const t=setTimeout(()=>{
el.style.opacity=0;
_hideTimers.delete(el);
},ms);
_hideTimers.set(el,t);
}
function _cancelHide(el){
const t=_hideTimers.get(el);
if(t){clearTimeout(t);_hideTimers.delete(el);}
}
function hideOldPrice(el,delay){
if(!el) return;
if(PRICE_ANIMATIONS && delay>0){
_scheduleHide(el,delay);
} else {
_cancelHide(el);
el.style.opacity=0;
}
}
function showOldPrice(el){
if(!el) return;
_cancelHide(el);
ensureShown(el);
el.style.opacity=1;
}
function updateDiscountBox(card,p){
const box=card.querySelector('.reducere-produs-shop');
const text=card.querySelector('.text-reducere-produs-shop');
if(!box||!text) return;
if(!p||p.discount_percent==null){
box.style.opacity=0;
return;
}
const v='-'+p.discount_percent+'%';
if(text.textContent!==v) text.textContent=v;
ensureShown(box);
box.style.opacity=1;
}
function updateStockBox(card,p){
const wrap=card.querySelector('.stoc-produs-shop');
const dot=card.querySelector('.punct-stoc-produs-shop');
const txt=card.querySelector('.text-stoc-produs-shop');
if(!wrap||!dot||!txt) return;
const status=p&&p.stock_status?String(p.stock_status):'';
const label=stockTextRo(status);
if(!label){
wrap.classList.remove('is-visible');
if(txt.textContent) txt.textContent='';
return;
}
if(txt.textContent!==label) txt.textContent=label;
const c=stockColor(status);
if(dot.style.backgroundColor!==c) dot.style.backgroundColor=c;
ensureShown(wrap);
wrap.classList.add('is-visible');
}
function updateDimensions(card,p){
const l=card.querySelector('.text-lungime-produs-shop');
const w=card.querySelector('.text-adancime-produs-shop');
const h=card.querySelector('.text-inaltime-produs-shop');
if(!l && !w && !h) return;
const unit=p&&p.dimension_unit?String(p.dimension_unit):'';
const L=p?p.length:null, W=p?p.width:null, H=p?p.height:null;
if(l){ const v=formatDim(L,unit); if(l.textContent!==v) l.textContent=v; }
if(w){ const v=formatDim(W,unit); if(w.textContent!==v) w.textContent=v; }
if(h){ const v=formatDim(H,unit); if(h.textContent!==v) h.textContent=v; }
}
function updatePrices(card,p){
const actual=card.querySelector('.pret-actual-produs-shop');
const oldWrap=card.querySelector('.wrap-pret-vechi-produs-shop');
const oldText=card.querySelector('.pret-vechi-produs-shop');
const oldBar =card.querySelector('.div-pret-vechi-produs-shop');
if(!actual) return;
const reg = p && p.regular_price!=null ? p.regular_price : null;
const sale= p && p.sale_price !=null ? p.sale_price : null;
// niciun preț valid
if(reg==null && sale==null){
if(actual.textContent) actual.textContent='';
if(oldWrap) hideOldPrice(oldWrap,0);
if(oldBar){
cancelOldBar(oldBar);
oldBar.style.minWidth='0%';
}
if(oldText&&oldText.textContent) oldText.textContent='';
return;
}
// există reducere reală
if(sale!=null && reg!=null && +sale>0 && +reg>0 && +sale<+reg){
const cur=nfRON(sale);
if(actual.textContent!==cur) actual.textContent=cur;
if(oldWrap) showOldPrice(oldWrap);
const regTxt=nfRON(reg);
if(oldText && oldText.textContent!==regTxt) oldText.textContent=regTxt;
if(oldBar){
cancelOldBar(oldBar);
if (PRICE_ANIMATIONS) {
scheduleOldBar(oldBar);
} else {
// fără animații -> fă bara vizibilă din nou
oldBar.style.minWidth = '110%';
}
}
return;
}
// fără reducere -> afișăm doar prețul normal și ascundem bara veche
const cur=nfRON(reg!=null?reg:sale);
if(actual.textContent!==cur) actual.textContent=cur;
if(oldBar){
cancelOldBar(oldBar);
oldBar.style.minWidth='0%';
}
if(oldWrap){
hideOldPrice(oldWrap, PRICE_ANIMATIONS ? 200 : 0);
}
}
function setMainImage(card, url){
const main=card.querySelector('[data-main-image]');
if(!main||!url) return;
if(main.dataset.mainSrc===url) return;
const pre=new Image();
pre.onload=function(){
if(main.dataset.mainSrc===url) return;
if(main.tagName==='IMG'){
main.setAttribute('src',url);
} else {
main.style.backgroundImage='url("'+url+'")';
}
main.dataset.mainSrc=url;
};
pre.src=url;
}
function setActiveItem(card, active){
forEach(card.querySelectorAll('[data-variation-item]'), el=>{
const act=el===active;
el.classList.toggle('is-active',act);
el.setAttribute('aria-selected', act?'true':'false');
});
}
const variationCache=new Map();
const prefetchQueue=new Set();
async function prefetchIds(ids){
const tasks=[];
ids.forEach(id=>{
if(!id) return;
if(!variationCache.has(id) && !prefetchQueue.has(id)){
prefetchQueue.add(id);
tasks.push(
fetchVariationData(id,0)
.then(d=>variationCache.set(id,d))
.catch(()=>variationCache.set(id,null))
.finally(()=>prefetchQueue.delete(id))
);
}
});
if(tasks.length) await Promise.allSettled(tasks);
}
async function prefetchAllIn(container){
const ids=new Set(
Array.from(container.querySelectorAll('[data-variation-item][data-variation-id]'))
.filter(el=>!isClone(el))
.map(el=>el.getAttribute('data-variation-id'))
.filter(Boolean)
);
await prefetchIds(ids);
}
async function initCard(card){
if(!card || card.dataset.init==='1') return;
if(isClone(card)) return;
card.dataset.init='1';
const firstItem=card.querySelector('[data-variation-item][data-variation-id]');
if(!firstItem) return;
setActiveItem(card, firstItem);
const vid=firstItem.getAttribute('data-variation-id');
const cached=variationCache.get(vid);
if(cached!==undefined){
updateDiscountBox(card,cached);
updateStockBox(card,cached);
updateDimensions(card,cached);
updatePrices(card,cached);
} else {
try{
const data=await fetchVariationData(vid,0);
variationCache.set(vid,data);
updateDiscountBox(card,data);
updateStockBox(card,data);
updateDimensions(card,data);
updatePrices(card,data);
}catch(e){
variationCache.set(vid, null);
}
}
const firstUrl=getFullUrlFromItem(firstItem);
if(firstUrl) setMainImage(card, firstUrl);
}
function initAllCards(root){
forEach((root||document).querySelectorAll('[data-product-card]'), card=>initCard(card));
}
// ==== SPLIDE MANAGER PER INSTANȚĂ ====
let ownSplide=null;
let rebuilding=false;
function getRoot(){
return document.getElementById(SPLIDE_ROOT_ID);
}
function readBricksOptions(rootEl){
try{
const raw=rootEl.getAttribute('data-splide');
if(!raw) return {};
const opts=JSON.parse(raw);
return Object.assign({ type:'slide', speed:400, perPage:4, gap:'1.3vw', autoHeight:false }, opts);
}catch(e){
return { type:'slide', gap:'1.3vw', autoHeight:false };
}
}
function detachBricksInstance(rootEl){
if(!rootEl) return;
const map = (window.bricksData && window.bricksData.splideInstances) || null;
if(map){
for(const k of Object.keys(map)){
const inst = map[k];
if(inst && (inst.root===rootEl || inst.root?.id===rootEl.id)){
try{ inst.destroy && inst.destroy(true); }catch(e){}
map[k]=null;
}
}
}
if(!rootEl.dataset.vh_splide_opts){
const opts = readBricksOptions(rootEl);
rootEl.dataset.vh_splide_opts = JSON.stringify(opts);
}
rootEl.removeAttribute('data-splide');
rootEl.classList.add('vh-splide-locked');
}
function resetInline(rootEl){
const track=rootEl.querySelector('.splide__track');
const list =rootEl.querySelector('.splide__list');
const slides=rootEl.querySelectorAll('.splide__slide');
if(track){ track.style.height=''; track.style.transform=''; }
if(list ){ list.style.height=''; list.style.transform=''; list.style.gap=''; }
slides.forEach(sl=>{
sl.style.height='';
sl.style.minHeight='';
sl.style.margin='';
});
}
function ensureStructure(rootEl){
let track = rootEl.querySelector('.splide__track');
let list = rootEl.querySelector('.splide__list');
if(!track){
track = document.createElement('div');
track.className='splide__track';
while(rootEl.firstChild) track.appendChild(rootEl.firstChild);
rootEl.appendChild(track);
}
if(!list){
list = document.createElement('ul');
list.className='splide__list';
const children = Array.from(track.children);
children.forEach(ch=>{
const li=document.createElement('li');
li.className='splide__slide';
li.appendChild(ch);
list.appendChild(li);
});
track.innerHTML='';
track.appendChild(list);
}
const kids = Array.from(list.children);
kids.forEach(li=>{
if(!li.classList.contains('splide__slide')){
li.classList.add('splide__slide');
}
});
list.querySelectorAll('.splide__slide--clone').forEach(c=>c.remove());
return {track, list};
}
function lockVisual(rootEl){
if (!rootEl) return;
const opts = (()=>{
try{ return JSON.parse(rootEl.dataset.vh_splide_opts || '{}'); } catch(e){ return {}; }
})();
rootEl.style.setProperty('--vh-gap', (opts.gap || '1.3vw'));
if (opts.fixedHeight) rootEl.style.setProperty('--vh-minh', opts.fixedHeight);
// ascundem până terminăm rebuild-ul
rootEl.style.setProperty('opacity', '0', 'important');
rootEl.style.setProperty('visibility', 'hidden', 'important');
rootEl.style.setProperty('pointer-events', 'none', 'important');
rootEl.classList.add('vh-prelayout','vh-mask');
}
function unlockVisual(rootEl){
if (!rootEl) return;
rootEl.style.removeProperty('opacity');
rootEl.style.removeProperty('visibility');
rootEl.style.removeProperty('pointer-events');
rootEl.classList.remove('vh-mask','vh-prelayout');
}
async function buildSplide(){
const rootEl=getRoot();
if(!rootEl || !window.Splide) return;
if(rebuilding) return;
rebuilding = true;
lockVisual(rootEl);
detachBricksInstance(rootEl);
resetInline(rootEl);
ensureStructure(rootEl);
const opts = (()=>{
try{ return JSON.parse(rootEl.dataset.vh_splide_opts || '{}'); } catch(e){ return {}; }
})();
if(ownSplide){
try{ ownSplide.destroy(true); }catch(e){}
ownSplide=null;
}
ownSplide = new Splide(rootEl, opts);
ownSplide.mount();
// stabilizare într-un frame înainte să-l arătăm
await new Promise(r=>requestAnimationFrame(()=>r()));
ownSplide.refresh();
ownSplide.emit && ownSplide.emit('resize');
unlockVisual(rootEl);
if(!window.bricksData) window.bricksData = {};
if(!window.bricksData.splideInstances) window.bricksData.splideInstances = {};
window.bricksData.splideInstances[SPLIDE_ROOT_ID + '__own'] = ownSplide;
rebuilding = false;
}
// debounce rebuild cu token, ca să nu dăm rebuild de 2 ori
let rebuildToken = 0;
let rebuildTimerRef = null;
function rebuildSplideDebounced(delay=100){
const myToken = ++rebuildToken;
if(rebuildTimerRef) clearTimeout(rebuildTimerRef);
rebuildTimerRef = setTimeout(()=>{
if(myToken !== rebuildToken) return;
buildSplide();
}, delay);
}
// ====== Variation click (schimbă variantă + UI card) ======
function onClickVariation(e){
const item=e.target.closest && e.target.closest('[data-variation-item][data-variation-id]');
if(!item) return;
const a=e.target.closest('a');
if(a && item.contains(a)) e.preventDefault();
const card=item.closest('[data-product-card]');
if(!card || isClone(card)) return;
const vid=item.getAttribute('data-variation-id');
setActiveItem(card,item);
const data=variationCache.get(vid);
if(data!==undefined){
updateDiscountBox(card,data);
updateStockBox(card,data);
updateDimensions(card,data);
updatePrices(card,data);
} else {
fetchVariationData(vid,0).then(d=>{
variationCache.set(vid,d);
updateDiscountBox(card,d);
updateStockBox(card,d);
updateDimensions(card,d);
updatePrices(card,d);
}).catch(()=>{
variationCache.set(vid,null);
});
// prefetch pentru restul variantelor din același card
const siblings = Array.from(
card.querySelectorAll('[data-variation-item][data-variation-id]')
).map(el=>el.getAttribute('data-variation-id'));
prefetchIds(new Set(siblings));
}
const fullUrl=getFullUrlFromItem(item);
if(fullUrl) setMainImage(card, fullUrl);
}
function attachHoverPrefetch(){
if(!HOVER_PREFETCH) return;
if(document.body.dataset.vhHoverBound==='1') return;
document.body.dataset.vhHoverBound='1';
document.addEventListener('mouseenter', e=>{
const it = e.target.closest && e.target.closest('[data-variation-item][data-variation-id]');
if(!it) return;
const vid = it.getAttribute('data-variation-id');
if(vid && !variationCache.has(vid)){
prefetchIds(new Set([vid]));
}
}, true);
}
// ====== Filter & observer ======
// stare doar pt sliderul ăsta
let awaitingDom = false;
let awaitingFallback= null;
let mo = null;
function attachFilterWatcher(){
const sel=document.getElementById(FILTER_SELECT_ID);
if(!sel || sel.dataset.vhBound==='1') return;
sel.dataset.vhBound='1';
sel.addEventListener('change', ()=>{
const rootEl=getRoot();
if(rootEl) lockVisual(rootEl); // ascundem sliderul vechi instant
awaitingDom = true; // așteptăm noul DOM după filtrare
// fallback dacă Bricks reordonează fără să schimbe nodurile într-un mod care declanșează observerul
if(awaitingFallback) clearTimeout(awaitingFallback);
awaitingFallback = setTimeout(()=>{
if(awaitingDom){
awaitingDom = false;
rebuildSplideDebounced(0);
}
}, 900);
// refacem cardurile după ce Bricks a actualizat conținutul intern
setTimeout(async ()=>{
const root=getRoot();
if(root){
const cont = root.querySelector('.splide__list') || root;
await prefetchAllIn(cont);
initAllCards(document);
}
}, 30);
});
}
function startObserver(){
if(mo) return;
mo=new MutationObserver((mut)=>{
const rootEl = getRoot();
if(!rootEl) return;
let touch = false;
let addedRoot = null;
for(const m of mut){
if(m.type!=='childList') continue;
// verificăm DOAR mutații care ating sliderul ăsta
m.addedNodes && m.addedNodes.forEach(n=>{
if(n.nodeType!==1) return;
// 1) dacă nodul adăugat ESTE chiar root-ul meu
if(n === rootEl){
touch=true;
addedRoot=rootEl;
return;
}
// 2) dacă nodul adăugat CONȚINE root-ul meu
if(n.contains && n.contains(rootEl)){
touch=true;
addedRoot=rootEl;
return;
}
// 3) dacă root-ul meu conține nodul adăugat (s-a schimbat conținutul intern al sliderului meu)
if(rootEl.contains(n)){
touch=true;
addedRoot=rootEl;
return;
}
});
}
if(!touch) return; // ignora mutațiile altor slider-e
// Am detectat modificare relevantă PENTRU sliderul acesta
const activeRoot = addedRoot || rootEl;
if(activeRoot) lockVisual(activeRoot); // îl ascundem până terminăm rebuild
if(awaitingDom){
// era un refresh de filtrare pentru sliderul ăsta
awaitingDom = false;
if(awaitingFallback){
clearTimeout(awaitingFallback);
awaitingFallback=null;
}
rebuildSplideDebounced(60); // rebuild rapid pt sliderul ăsta
} else {
// doar o mică mutație (ex. resize/reflow etc.)
rebuildSplideDebounced(100);
}
// re-init la carduri după ce DOM-ul nou e acolo
setTimeout(()=>initAllCards(document), 20);
});
// Observăm tot body-ul, dar în callback filtrăm strict pe root-ul ăsta
mo.observe(document.body,{childList:true,subtree:true});
}
// ====== ENTRY POINT ======
onReady(async function(){
const root0 = getRoot();
if (root0) await prefetchAllIn(root0);
initAllCards(document);
if(!document.body.dataset.vhClickBound){
document.addEventListener('click', onClickVariation);
document.body.dataset.vhClickBound='1';
}
attachHoverPrefetch();
attachFilterWatcher();
startObserver();
if(root0){
const opts = readBricksOptions(root0);
root0.style.setProperty('--vh-gap', (opts.gap || '1.3vw'));
if (opts.fixedHeight) root0.style.setProperty('--vh-minh', opts.fixedHeight);
}
buildSplide();
window.addEventListener('resize', ()=>{
rebuildSplideDebounced(100);
}, {passive:true});
});
})();
</script>
asf
L
90cm
I
90cm
A
90cm
976 RON
976 RON
Aplică codul SPEED20 pentru -20% reducere
<style>
/* Ascunde complet sliderul PÂNĂ e 100% montat (fără fade/blink) */
#brxe-akucji.vh-mask {
opacity: 0 !important;
visibility: hidden !important;
pointer-events: none !important;
}
/* Prelayout: imităm EXACT ce va face Splide după mount,
ca să nu existe schimbare vizuală la gap/înălțime */
#brxe-akucji.vh-prelayout .splide__list {
display: flex;
}
#brxe-akucji.vh-prelayout .splide__slide {
margin-right: var(--vh-gap, 1.3vw);
min-height: var(--vh-minh, 36rem);
}
</style>
<script>
(function(){
const SPLIDE_ROOT_ID = 'brxe-akucji'; // <-- schimbi pt instanța 2
const FILTER_SELECT_ID = 'brxe-dsvvdo'; // <-- schimbi pt instanța 2
const PRICE_ANIMATIONS = false;
const HOVER_PREFETCH = true;
function onReady(fn){
if(document.readyState==='loading'){
document.addEventListener('DOMContentLoaded', fn,{once:true});
} else {
fn();
}
}
function getApiRoot(){
return (window.wpApiSettings && window.wpApiSettings.root) || '/wp-json/';
}
async function fetchVariationData(variationId, decimals){
const url = getApiRoot() + 'my/v1/variation-discount/' + encodeURIComponent(variationId) + '?decimals=' + (decimals ?? 0);
const res = await fetch(url, { credentials:'same-origin' });
if(!res.ok) throw new Error('HTTP '+res.status);
return res.json();
}
const forEach = (nl, cb)=> Array.prototype.forEach.call(nl, cb);
const isClone = el => !!el.closest('.splide__slide--clone');
function ensureShown(el){
if(el && getComputedStyle(el).display==='none'){
el.style.setProperty('display','flex','important');
}
}
function nfRON(val){
if(val==null||val==='') return '';
const n=Number(val);
if(!Number.isFinite(n)) return '';
return new Intl.NumberFormat('ro-RO',{minimumFractionDigits:0,maximumFractionDigits:2}).format(n)+' RON';
}
function stockTextRo(s){
return s==='instock'?'În stoc'
:s==='outofstock'?'Stoc epuizat'
:s==='onbackorder'?'În stoc furnizor'
:'';
}
function stockColor(s){
return s==='instock' ?'#00E832'
:s==='outofstock' ?'#FF0000'
:s==='onbackorder' ?'#ffb22e'
:'#9ca3af';
}
function formatDim(v,u){
if(v==null||v==='') return '';
return `${v}${u||''}`.trim();
}
function getFullUrlFromItem(item){
if(!item) return '';
const d=item.getAttribute('data-url'); if(d) return d;
const a=item.querySelector('a[href]'); if(a&&a.href) return a.href;
const img=item.querySelector('img'); if(img) return img.currentSrc||img.src||'';
return '';
}
const _barTimers=new WeakMap(), _hideTimers=new WeakMap();
function cancelOldBar(el){
const t=_barTimers.get(el);
if(t){clearTimeout(t);_barTimers.delete(el);}
}
function animateOldPriceBar(barEl){
if (!PRICE_ANIMATIONS || !barEl) return;
const t = barEl.style.transition;
if (!t || !/min-width/.test(t)){
barEl.style.transition = 'min-width .2s ease-in-out';
}
barEl.style.minWidth = '0%';
void barEl.offsetWidth;
barEl.style.minWidth = '110%';
}
function scheduleOldBar(el){
if(!PRICE_ANIMATIONS) return;
cancelOldBar(el);
const t=setTimeout(()=>{
animateOldPriceBar(el);
_barTimers.delete(el);
}, 0);
_barTimers.set(el,t);
}
function _scheduleHide(el,ms){
if(!PRICE_ANIMATIONS){
el.style.opacity=0;
return;
}
if(!el) return;
_cancelHide(el);
const t=setTimeout(()=>{
el.style.opacity=0;
_hideTimers.delete(el);
},ms);
_hideTimers.set(el,t);
}
function _cancelHide(el){
const t=_hideTimers.get(el);
if(t){clearTimeout(t);_hideTimers.delete(el);}
}
function hideOldPrice(el,delay){
if(!el) return;
if(PRICE_ANIMATIONS && delay>0){
_scheduleHide(el,delay);
} else {
_cancelHide(el);
el.style.opacity=0;
}
}
function showOldPrice(el){
if(!el) return;
_cancelHide(el);
ensureShown(el);
el.style.opacity=1;
}
function updateDiscountBox(card,p){
const box=card.querySelector('.reducere-produs-shop');
const text=card.querySelector('.text-reducere-produs-shop');
if(!box||!text) return;
if(!p||p.discount_percent==null){
box.style.opacity=0;
return;
}
const v='-'+p.discount_percent+'%';
if(text.textContent!==v) text.textContent=v;
ensureShown(box);
box.style.opacity=1;
}
function updateStockBox(card,p){
const wrap=card.querySelector('.stoc-produs-shop');
const dot=card.querySelector('.punct-stoc-produs-shop');
const txt=card.querySelector('.text-stoc-produs-shop');
if(!wrap||!dot||!txt) return;
const status=p&&p.stock_status?String(p.stock_status):'';
const label=stockTextRo(status);
if(!label){
wrap.classList.remove('is-visible');
if(txt.textContent) txt.textContent='';
return;
}
if(txt.textContent!==label) txt.textContent=label;
const c=stockColor(status);
if(dot.style.backgroundColor!==c) dot.style.backgroundColor=c;
ensureShown(wrap);
wrap.classList.add('is-visible');
}
function updateDimensions(card,p){
const l=card.querySelector('.text-lungime-produs-shop');
const w=card.querySelector('.text-adancime-produs-shop');
const h=card.querySelector('.text-inaltime-produs-shop');
if(!l && !w && !h) return;
const unit=p&&p.dimension_unit?String(p.dimension_unit):'';
const L=p?p.length:null, W=p?p.width:null, H=p?p.height:null;
if(l){ const v=formatDim(L,unit); if(l.textContent!==v) l.textContent=v; }
if(w){ const v=formatDim(W,unit); if(w.textContent!==v) w.textContent=v; }
if(h){ const v=formatDim(H,unit); if(h.textContent!==v) h.textContent=v; }
}
function updatePrices(card,p){
const actual=card.querySelector('.pret-actual-produs-shop');
const oldWrap=card.querySelector('.wrap-pret-vechi-produs-shop');
const oldText=card.querySelector('.pret-vechi-produs-shop');
const oldBar =card.querySelector('.div-pret-vechi-produs-shop');
if(!actual) return;
const reg = p && p.regular_price!=null ? p.regular_price : null;
const sale= p && p.sale_price !=null ? p.sale_price : null;
// niciun preț valid
if(reg==null && sale==null){
if(actual.textContent) actual.textContent='';
if(oldWrap) hideOldPrice(oldWrap,0);
if(oldBar){
cancelOldBar(oldBar);
oldBar.style.minWidth='0%';
}
if(oldText&&oldText.textContent) oldText.textContent='';
return;
}
// există reducere reală
if(sale!=null && reg!=null && +sale>0 && +reg>0 && +sale<+reg){
const cur=nfRON(sale);
if(actual.textContent!==cur) actual.textContent=cur;
if(oldWrap) showOldPrice(oldWrap);
const regTxt=nfRON(reg);
if(oldText && oldText.textContent!==regTxt) oldText.textContent=regTxt;
if(oldBar){
cancelOldBar(oldBar);
if (PRICE_ANIMATIONS) {
scheduleOldBar(oldBar);
} else {
// fără animații -> fă bara vizibilă din nou
oldBar.style.minWidth = '110%';
}
}
return;
}
// fără reducere -> afișăm doar prețul normal și ascundem bara veche
const cur=nfRON(reg!=null?reg:sale);
if(actual.textContent!==cur) actual.textContent=cur;
if(oldBar){
cancelOldBar(oldBar);
oldBar.style.minWidth='0%';
}
if(oldWrap){
hideOldPrice(oldWrap, PRICE_ANIMATIONS ? 200 : 0);
}
}
function setMainImage(card, url){
const main=card.querySelector('[data-main-image]');
if(!main||!url) return;
if(main.dataset.mainSrc===url) return;
const pre=new Image();
pre.onload=function(){
if(main.dataset.mainSrc===url) return;
if(main.tagName==='IMG'){
main.setAttribute('src',url);
} else {
main.style.backgroundImage='url("'+url+'")';
}
main.dataset.mainSrc=url;
};
pre.src=url;
}
function setActiveItem(card, active){
forEach(card.querySelectorAll('[data-variation-item]'), el=>{
const act=el===active;
el.classList.toggle('is-active',act);
el.setAttribute('aria-selected', act?'true':'false');
});
}
const variationCache=new Map();
const prefetchQueue=new Set();
async function prefetchIds(ids){
const tasks=[];
ids.forEach(id=>{
if(!id) return;
if(!variationCache.has(id) && !prefetchQueue.has(id)){
prefetchQueue.add(id);
tasks.push(
fetchVariationData(id,0)
.then(d=>variationCache.set(id,d))
.catch(()=>variationCache.set(id,null))
.finally(()=>prefetchQueue.delete(id))
);
}
});
if(tasks.length) await Promise.allSettled(tasks);
}
async function prefetchAllIn(container){
const ids=new Set(
Array.from(container.querySelectorAll('[data-variation-item][data-variation-id]'))
.filter(el=>!isClone(el))
.map(el=>el.getAttribute('data-variation-id'))
.filter(Boolean)
);
await prefetchIds(ids);
}
async function initCard(card){
if(!card || card.dataset.init==='1') return;
if(isClone(card)) return;
card.dataset.init='1';
const firstItem=card.querySelector('[data-variation-item][data-variation-id]');
if(!firstItem) return;
setActiveItem(card, firstItem);
const vid=firstItem.getAttribute('data-variation-id');
const cached=variationCache.get(vid);
if(cached!==undefined){
updateDiscountBox(card,cached);
updateStockBox(card,cached);
updateDimensions(card,cached);
updatePrices(card,cached);
} else {
try{
const data=await fetchVariationData(vid,0);
variationCache.set(vid,data);
updateDiscountBox(card,data);
updateStockBox(card,data);
updateDimensions(card,data);
updatePrices(card,data);
}catch(e){
variationCache.set(vid, null);
}
}
const firstUrl=getFullUrlFromItem(firstItem);
if(firstUrl) setMainImage(card, firstUrl);
}
function initAllCards(root){
forEach((root||document).querySelectorAll('[data-product-card]'), card=>initCard(card));
}
// ==== SPLIDE MANAGER PER INSTANȚĂ ====
let ownSplide=null;
let rebuilding=false;
function getRoot(){
return document.getElementById(SPLIDE_ROOT_ID);
}
function readBricksOptions(rootEl){
try{
const raw=rootEl.getAttribute('data-splide');
if(!raw) return {};
const opts=JSON.parse(raw);
return Object.assign({ type:'slide', speed:400, perPage:4, gap:'1.3vw', autoHeight:false }, opts);
}catch(e){
return { type:'slide', gap:'1.3vw', autoHeight:false };
}
}
function detachBricksInstance(rootEl){
if(!rootEl) return;
const map = (window.bricksData && window.bricksData.splideInstances) || null;
if(map){
for(const k of Object.keys(map)){
const inst = map[k];
if(inst && (inst.root===rootEl || inst.root?.id===rootEl.id)){
try{ inst.destroy && inst.destroy(true); }catch(e){}
map[k]=null;
}
}
}
if(!rootEl.dataset.vh_splide_opts){
const opts = readBricksOptions(rootEl);
rootEl.dataset.vh_splide_opts = JSON.stringify(opts);
}
rootEl.removeAttribute('data-splide');
rootEl.classList.add('vh-splide-locked');
}
function resetInline(rootEl){
const track=rootEl.querySelector('.splide__track');
const list =rootEl.querySelector('.splide__list');
const slides=rootEl.querySelectorAll('.splide__slide');
if(track){ track.style.height=''; track.style.transform=''; }
if(list ){ list.style.height=''; list.style.transform=''; list.style.gap=''; }
slides.forEach(sl=>{
sl.style.height='';
sl.style.minHeight='';
sl.style.margin='';
});
}
function ensureStructure(rootEl){
let track = rootEl.querySelector('.splide__track');
let list = rootEl.querySelector('.splide__list');
if(!track){
track = document.createElement('div');
track.className='splide__track';
while(rootEl.firstChild) track.appendChild(rootEl.firstChild);
rootEl.appendChild(track);
}
if(!list){
list = document.createElement('ul');
list.className='splide__list';
const children = Array.from(track.children);
children.forEach(ch=>{
const li=document.createElement('li');
li.className='splide__slide';
li.appendChild(ch);
list.appendChild(li);
});
track.innerHTML='';
track.appendChild(list);
}
const kids = Array.from(list.children);
kids.forEach(li=>{
if(!li.classList.contains('splide__slide')){
li.classList.add('splide__slide');
}
});
list.querySelectorAll('.splide__slide--clone').forEach(c=>c.remove());
return {track, list};
}
function lockVisual(rootEl){
if (!rootEl) return;
const opts = (()=>{
try{ return JSON.parse(rootEl.dataset.vh_splide_opts || '{}'); } catch(e){ return {}; }
})();
rootEl.style.setProperty('--vh-gap', (opts.gap || '1.3vw'));
if (opts.fixedHeight) rootEl.style.setProperty('--vh-minh', opts.fixedHeight);
// ascundem până terminăm rebuild-ul
rootEl.style.setProperty('opacity', '0', 'important');
rootEl.style.setProperty('visibility', 'hidden', 'important');
rootEl.style.setProperty('pointer-events', 'none', 'important');
rootEl.classList.add('vh-prelayout','vh-mask');
}
function unlockVisual(rootEl){
if (!rootEl) return;
rootEl.style.removeProperty('opacity');
rootEl.style.removeProperty('visibility');
rootEl.style.removeProperty('pointer-events');
rootEl.classList.remove('vh-mask','vh-prelayout');
}
async function buildSplide(){
const rootEl=getRoot();
if(!rootEl || !window.Splide) return;
if(rebuilding) return;
rebuilding = true;
lockVisual(rootEl);
detachBricksInstance(rootEl);
resetInline(rootEl);
ensureStructure(rootEl);
const opts = (()=>{
try{ return JSON.parse(rootEl.dataset.vh_splide_opts || '{}'); } catch(e){ return {}; }
})();
if(ownSplide){
try{ ownSplide.destroy(true); }catch(e){}
ownSplide=null;
}
ownSplide = new Splide(rootEl, opts);
ownSplide.mount();
// stabilizare într-un frame înainte să-l arătăm
await new Promise(r=>requestAnimationFrame(()=>r()));
ownSplide.refresh();
ownSplide.emit && ownSplide.emit('resize');
unlockVisual(rootEl);
if(!window.bricksData) window.bricksData = {};
if(!window.bricksData.splideInstances) window.bricksData.splideInstances = {};
window.bricksData.splideInstances[SPLIDE_ROOT_ID + '__own'] = ownSplide;
rebuilding = false;
}
// debounce rebuild cu token, ca să nu dăm rebuild de 2 ori
let rebuildToken = 0;
let rebuildTimerRef = null;
function rebuildSplideDebounced(delay=100){
const myToken = ++rebuildToken;
if(rebuildTimerRef) clearTimeout(rebuildTimerRef);
rebuildTimerRef = setTimeout(()=>{
if(myToken !== rebuildToken) return;
buildSplide();
}, delay);
}
// ====== Variation click (schimbă variantă + UI card) ======
function onClickVariation(e){
const item=e.target.closest && e.target.closest('[data-variation-item][data-variation-id]');
if(!item) return;
const a=e.target.closest('a');
if(a && item.contains(a)) e.preventDefault();
const card=item.closest('[data-product-card]');
if(!card || isClone(card)) return;
const vid=item.getAttribute('data-variation-id');
setActiveItem(card,item);
const data=variationCache.get(vid);
if(data!==undefined){
updateDiscountBox(card,data);
updateStockBox(card,data);
updateDimensions(card,data);
updatePrices(card,data);
} else {
fetchVariationData(vid,0).then(d=>{
variationCache.set(vid,d);
updateDiscountBox(card,d);
updateStockBox(card,d);
updateDimensions(card,d);
updatePrices(card,d);
}).catch(()=>{
variationCache.set(vid,null);
});
// prefetch pentru restul variantelor din același card
const siblings = Array.from(
card.querySelectorAll('[data-variation-item][data-variation-id]')
).map(el=>el.getAttribute('data-variation-id'));
prefetchIds(new Set(siblings));
}
const fullUrl=getFullUrlFromItem(item);
if(fullUrl) setMainImage(card, fullUrl);
}
function attachHoverPrefetch(){
if(!HOVER_PREFETCH) return;
if(document.body.dataset.vhHoverBound==='1') return;
document.body.dataset.vhHoverBound='1';
document.addEventListener('mouseenter', e=>{
const it = e.target.closest && e.target.closest('[data-variation-item][data-variation-id]');
if(!it) return;
const vid = it.getAttribute('data-variation-id');
if(vid && !variationCache.has(vid)){
prefetchIds(new Set([vid]));
}
}, true);
}
// ====== Filter & observer ======
// stare doar pt sliderul ăsta
let awaitingDom = false;
let awaitingFallback= null;
let mo = null;
function attachFilterWatcher(){
const sel=document.getElementById(FILTER_SELECT_ID);
if(!sel || sel.dataset.vhBound==='1') return;
sel.dataset.vhBound='1';
sel.addEventListener('change', ()=>{
const rootEl=getRoot();
if(rootEl) lockVisual(rootEl); // ascundem sliderul vechi instant
awaitingDom = true; // așteptăm noul DOM după filtrare
// fallback dacă Bricks reordonează fără să schimbe nodurile într-un mod care declanșează observerul
if(awaitingFallback) clearTimeout(awaitingFallback);
awaitingFallback = setTimeout(()=>{
if(awaitingDom){
awaitingDom = false;
rebuildSplideDebounced(0);
}
}, 900);
// refacem cardurile după ce Bricks a actualizat conținutul intern
setTimeout(async ()=>{
const root=getRoot();
if(root){
const cont = root.querySelector('.splide__list') || root;
await prefetchAllIn(cont);
initAllCards(document);
}
}, 30);
});
}
function startObserver(){
if(mo) return;
mo=new MutationObserver((mut)=>{
const rootEl = getRoot();
if(!rootEl) return;
let touch = false;
let addedRoot = null;
for(const m of mut){
if(m.type!=='childList') continue;
// verificăm DOAR mutații care ating sliderul ăsta
m.addedNodes && m.addedNodes.forEach(n=>{
if(n.nodeType!==1) return;
// 1) dacă nodul adăugat ESTE chiar root-ul meu
if(n === rootEl){
touch=true;
addedRoot=rootEl;
return;
}
// 2) dacă nodul adăugat CONȚINE root-ul meu
if(n.contains && n.contains(rootEl)){
touch=true;
addedRoot=rootEl;
return;
}
// 3) dacă root-ul meu conține nodul adăugat (s-a schimbat conținutul intern al sliderului meu)
if(rootEl.contains(n)){
touch=true;
addedRoot=rootEl;
return;
}
});
}
if(!touch) return; // ignora mutațiile altor slider-e
// Am detectat modificare relevantă PENTRU sliderul acesta
const activeRoot = addedRoot || rootEl;
if(activeRoot) lockVisual(activeRoot); // îl ascundem până terminăm rebuild
if(awaitingDom){
// era un refresh de filtrare pentru sliderul ăsta
awaitingDom = false;
if(awaitingFallback){
clearTimeout(awaitingFallback);
awaitingFallback=null;
}
rebuildSplideDebounced(60); // rebuild rapid pt sliderul ăsta
} else {
// doar o mică mutație (ex. resize/reflow etc.)
rebuildSplideDebounced(100);
}
// re-init la carduri după ce DOM-ul nou e acolo
setTimeout(()=>initAllCards(document), 20);
});
// Observăm tot body-ul, dar în callback filtrăm strict pe root-ul ăsta
mo.observe(document.body,{childList:true,subtree:true});
}
// ====== ENTRY POINT ======
onReady(async function(){
const root0 = getRoot();
if (root0) await prefetchAllIn(root0);
initAllCards(document);
if(!document.body.dataset.vhClickBound){
document.addEventListener('click', onClickVariation);
document.body.dataset.vhClickBound='1';
}
attachHoverPrefetch();
attachFilterWatcher();
startObserver();
if(root0){
const opts = readBricksOptions(root0);
root0.style.setProperty('--vh-gap', (opts.gap || '1.3vw'));
if (opts.fixedHeight) root0.style.setProperty('--vh-minh', opts.fixedHeight);
}
buildSplide();
window.addEventListener('resize', ()=>{
rebuildSplideDebounced(100);
}, {passive:true});
});
})();
</script>
asf
Masa cafea
In stoc
L
90cm
I
90cm
A
90cm
976 RON
976 RON
Aplică codul SPEED20 pentru -20% reducere
<style>
/* Ascunde complet sliderul PÂNĂ e 100% montat (fără fade/blink) */
#brxe-akucji.vh-mask {
opacity: 0 !important;
visibility: hidden !important;
pointer-events: none !important;
}
/* Prelayout: imităm EXACT ce va face Splide după mount,
ca să nu existe schimbare vizuală la gap/înălțime */
#brxe-akucji.vh-prelayout .splide__list {
display: flex;
}
#brxe-akucji.vh-prelayout .splide__slide {
margin-right: var(--vh-gap, 1.3vw);
min-height: var(--vh-minh, 36rem);
}
</style>
<script>
(function(){
const SPLIDE_ROOT_ID = 'brxe-akucji'; // <-- schimbi pt instanța 2
const FILTER_SELECT_ID = 'brxe-dsvvdo'; // <-- schimbi pt instanța 2
const PRICE_ANIMATIONS = false;
const HOVER_PREFETCH = true;
function onReady(fn){
if(document.readyState==='loading'){
document.addEventListener('DOMContentLoaded', fn,{once:true});
} else {
fn();
}
}
function getApiRoot(){
return (window.wpApiSettings && window.wpApiSettings.root) || '/wp-json/';
}
async function fetchVariationData(variationId, decimals){
const url = getApiRoot() + 'my/v1/variation-discount/' + encodeURIComponent(variationId) + '?decimals=' + (decimals ?? 0);
const res = await fetch(url, { credentials:'same-origin' });
if(!res.ok) throw new Error('HTTP '+res.status);
return res.json();
}
const forEach = (nl, cb)=> Array.prototype.forEach.call(nl, cb);
const isClone = el => !!el.closest('.splide__slide--clone');
function ensureShown(el){
if(el && getComputedStyle(el).display==='none'){
el.style.setProperty('display','flex','important');
}
}
function nfRON(val){
if(val==null||val==='') return '';
const n=Number(val);
if(!Number.isFinite(n)) return '';
return new Intl.NumberFormat('ro-RO',{minimumFractionDigits:0,maximumFractionDigits:2}).format(n)+' RON';
}
function stockTextRo(s){
return s==='instock'?'În stoc'
:s==='outofstock'?'Stoc epuizat'
:s==='onbackorder'?'În stoc furnizor'
:'';
}
function stockColor(s){
return s==='instock' ?'#00E832'
:s==='outofstock' ?'#FF0000'
:s==='onbackorder' ?'#ffb22e'
:'#9ca3af';
}
function formatDim(v,u){
if(v==null||v==='') return '';
return `${v}${u||''}`.trim();
}
function getFullUrlFromItem(item){
if(!item) return '';
const d=item.getAttribute('data-url'); if(d) return d;
const a=item.querySelector('a[href]'); if(a&&a.href) return a.href;
const img=item.querySelector('img'); if(img) return img.currentSrc||img.src||'';
return '';
}
const _barTimers=new WeakMap(), _hideTimers=new WeakMap();
function cancelOldBar(el){
const t=_barTimers.get(el);
if(t){clearTimeout(t);_barTimers.delete(el);}
}
function animateOldPriceBar(barEl){
if (!PRICE_ANIMATIONS || !barEl) return;
const t = barEl.style.transition;
if (!t || !/min-width/.test(t)){
barEl.style.transition = 'min-width .2s ease-in-out';
}
barEl.style.minWidth = '0%';
void barEl.offsetWidth;
barEl.style.minWidth = '110%';
}
function scheduleOldBar(el){
if(!PRICE_ANIMATIONS) return;
cancelOldBar(el);
const t=setTimeout(()=>{
animateOldPriceBar(el);
_barTimers.delete(el);
}, 0);
_barTimers.set(el,t);
}
function _scheduleHide(el,ms){
if(!PRICE_ANIMATIONS){
el.style.opacity=0;
return;
}
if(!el) return;
_cancelHide(el);
const t=setTimeout(()=>{
el.style.opacity=0;
_hideTimers.delete(el);
},ms);
_hideTimers.set(el,t);
}
function _cancelHide(el){
const t=_hideTimers.get(el);
if(t){clearTimeout(t);_hideTimers.delete(el);}
}
function hideOldPrice(el,delay){
if(!el) return;
if(PRICE_ANIMATIONS && delay>0){
_scheduleHide(el,delay);
} else {
_cancelHide(el);
el.style.opacity=0;
}
}
function showOldPrice(el){
if(!el) return;
_cancelHide(el);
ensureShown(el);
el.style.opacity=1;
}
function updateDiscountBox(card,p){
const box=card.querySelector('.reducere-produs-shop');
const text=card.querySelector('.text-reducere-produs-shop');
if(!box||!text) return;
if(!p||p.discount_percent==null){
box.style.opacity=0;
return;
}
const v='-'+p.discount_percent+'%';
if(text.textContent!==v) text.textContent=v;
ensureShown(box);
box.style.opacity=1;
}
function updateStockBox(card,p){
const wrap=card.querySelector('.stoc-produs-shop');
const dot=card.querySelector('.punct-stoc-produs-shop');
const txt=card.querySelector('.text-stoc-produs-shop');
if(!wrap||!dot||!txt) return;
const status=p&&p.stock_status?String(p.stock_status):'';
const label=stockTextRo(status);
if(!label){
wrap.classList.remove('is-visible');
if(txt.textContent) txt.textContent='';
return;
}
if(txt.textContent!==label) txt.textContent=label;
const c=stockColor(status);
if(dot.style.backgroundColor!==c) dot.style.backgroundColor=c;
ensureShown(wrap);
wrap.classList.add('is-visible');
}
function updateDimensions(card,p){
const l=card.querySelector('.text-lungime-produs-shop');
const w=card.querySelector('.text-adancime-produs-shop');
const h=card.querySelector('.text-inaltime-produs-shop');
if(!l && !w && !h) return;
const unit=p&&p.dimension_unit?String(p.dimension_unit):'';
const L=p?p.length:null, W=p?p.width:null, H=p?p.height:null;
if(l){ const v=formatDim(L,unit); if(l.textContent!==v) l.textContent=v; }
if(w){ const v=formatDim(W,unit); if(w.textContent!==v) w.textContent=v; }
if(h){ const v=formatDim(H,unit); if(h.textContent!==v) h.textContent=v; }
}
function updatePrices(card,p){
const actual=card.querySelector('.pret-actual-produs-shop');
const oldWrap=card.querySelector('.wrap-pret-vechi-produs-shop');
const oldText=card.querySelector('.pret-vechi-produs-shop');
const oldBar =card.querySelector('.div-pret-vechi-produs-shop');
if(!actual) return;
const reg = p && p.regular_price!=null ? p.regular_price : null;
const sale= p && p.sale_price !=null ? p.sale_price : null;
// niciun preț valid
if(reg==null && sale==null){
if(actual.textContent) actual.textContent='';
if(oldWrap) hideOldPrice(oldWrap,0);
if(oldBar){
cancelOldBar(oldBar);
oldBar.style.minWidth='0%';
}
if(oldText&&oldText.textContent) oldText.textContent='';
return;
}
// există reducere reală
if(sale!=null && reg!=null && +sale>0 && +reg>0 && +sale<+reg){
const cur=nfRON(sale);
if(actual.textContent!==cur) actual.textContent=cur;
if(oldWrap) showOldPrice(oldWrap);
const regTxt=nfRON(reg);
if(oldText && oldText.textContent!==regTxt) oldText.textContent=regTxt;
if(oldBar){
cancelOldBar(oldBar);
if (PRICE_ANIMATIONS) {
scheduleOldBar(oldBar);
} else {
// fără animații -> fă bara vizibilă din nou
oldBar.style.minWidth = '110%';
}
}
return;
}
// fără reducere -> afișăm doar prețul normal și ascundem bara veche
const cur=nfRON(reg!=null?reg:sale);
if(actual.textContent!==cur) actual.textContent=cur;
if(oldBar){
cancelOldBar(oldBar);
oldBar.style.minWidth='0%';
}
if(oldWrap){
hideOldPrice(oldWrap, PRICE_ANIMATIONS ? 200 : 0);
}
}
function setMainImage(card, url){
const main=card.querySelector('[data-main-image]');
if(!main||!url) return;
if(main.dataset.mainSrc===url) return;
const pre=new Image();
pre.onload=function(){
if(main.dataset.mainSrc===url) return;
if(main.tagName==='IMG'){
main.setAttribute('src',url);
} else {
main.style.backgroundImage='url("'+url+'")';
}
main.dataset.mainSrc=url;
};
pre.src=url;
}
function setActiveItem(card, active){
forEach(card.querySelectorAll('[data-variation-item]'), el=>{
const act=el===active;
el.classList.toggle('is-active',act);
el.setAttribute('aria-selected', act?'true':'false');
});
}
const variationCache=new Map();
const prefetchQueue=new Set();
async function prefetchIds(ids){
const tasks=[];
ids.forEach(id=>{
if(!id) return;
if(!variationCache.has(id) && !prefetchQueue.has(id)){
prefetchQueue.add(id);
tasks.push(
fetchVariationData(id,0)
.then(d=>variationCache.set(id,d))
.catch(()=>variationCache.set(id,null))
.finally(()=>prefetchQueue.delete(id))
);
}
});
if(tasks.length) await Promise.allSettled(tasks);
}
async function prefetchAllIn(container){
const ids=new Set(
Array.from(container.querySelectorAll('[data-variation-item][data-variation-id]'))
.filter(el=>!isClone(el))
.map(el=>el.getAttribute('data-variation-id'))
.filter(Boolean)
);
await prefetchIds(ids);
}
async function initCard(card){
if(!card || card.dataset.init==='1') return;
if(isClone(card)) return;
card.dataset.init='1';
const firstItem=card.querySelector('[data-variation-item][data-variation-id]');
if(!firstItem) return;
setActiveItem(card, firstItem);
const vid=firstItem.getAttribute('data-variation-id');
const cached=variationCache.get(vid);
if(cached!==undefined){
updateDiscountBox(card,cached);
updateStockBox(card,cached);
updateDimensions(card,cached);
updatePrices(card,cached);
} else {
try{
const data=await fetchVariationData(vid,0);
variationCache.set(vid,data);
updateDiscountBox(card,data);
updateStockBox(card,data);
updateDimensions(card,data);
updatePrices(card,data);
}catch(e){
variationCache.set(vid, null);
}
}
const firstUrl=getFullUrlFromItem(firstItem);
if(firstUrl) setMainImage(card, firstUrl);
}
function initAllCards(root){
forEach((root||document).querySelectorAll('[data-product-card]'), card=>initCard(card));
}
// ==== SPLIDE MANAGER PER INSTANȚĂ ====
let ownSplide=null;
let rebuilding=false;
function getRoot(){
return document.getElementById(SPLIDE_ROOT_ID);
}
function readBricksOptions(rootEl){
try{
const raw=rootEl.getAttribute('data-splide');
if(!raw) return {};
const opts=JSON.parse(raw);
return Object.assign({ type:'slide', speed:400, perPage:4, gap:'1.3vw', autoHeight:false }, opts);
}catch(e){
return { type:'slide', gap:'1.3vw', autoHeight:false };
}
}
function detachBricksInstance(rootEl){
if(!rootEl) return;
const map = (window.bricksData && window.bricksData.splideInstances) || null;
if(map){
for(const k of Object.keys(map)){
const inst = map[k];
if(inst && (inst.root===rootEl || inst.root?.id===rootEl.id)){
try{ inst.destroy && inst.destroy(true); }catch(e){}
map[k]=null;
}
}
}
if(!rootEl.dataset.vh_splide_opts){
const opts = readBricksOptions(rootEl);
rootEl.dataset.vh_splide_opts = JSON.stringify(opts);
}
rootEl.removeAttribute('data-splide');
rootEl.classList.add('vh-splide-locked');
}
function resetInline(rootEl){
const track=rootEl.querySelector('.splide__track');
const list =rootEl.querySelector('.splide__list');
const slides=rootEl.querySelectorAll('.splide__slide');
if(track){ track.style.height=''; track.style.transform=''; }
if(list ){ list.style.height=''; list.style.transform=''; list.style.gap=''; }
slides.forEach(sl=>{
sl.style.height='';
sl.style.minHeight='';
sl.style.margin='';
});
}
function ensureStructure(rootEl){
let track = rootEl.querySelector('.splide__track');
let list = rootEl.querySelector('.splide__list');
if(!track){
track = document.createElement('div');
track.className='splide__track';
while(rootEl.firstChild) track.appendChild(rootEl.firstChild);
rootEl.appendChild(track);
}
if(!list){
list = document.createElement('ul');
list.className='splide__list';
const children = Array.from(track.children);
children.forEach(ch=>{
const li=document.createElement('li');
li.className='splide__slide';
li.appendChild(ch);
list.appendChild(li);
});
track.innerHTML='';
track.appendChild(list);
}
const kids = Array.from(list.children);
kids.forEach(li=>{
if(!li.classList.contains('splide__slide')){
li.classList.add('splide__slide');
}
});
list.querySelectorAll('.splide__slide--clone').forEach(c=>c.remove());
return {track, list};
}
function lockVisual(rootEl){
if (!rootEl) return;
const opts = (()=>{
try{ return JSON.parse(rootEl.dataset.vh_splide_opts || '{}'); } catch(e){ return {}; }
})();
rootEl.style.setProperty('--vh-gap', (opts.gap || '1.3vw'));
if (opts.fixedHeight) rootEl.style.setProperty('--vh-minh', opts.fixedHeight);
// ascundem până terminăm rebuild-ul
rootEl.style.setProperty('opacity', '0', 'important');
rootEl.style.setProperty('visibility', 'hidden', 'important');
rootEl.style.setProperty('pointer-events', 'none', 'important');
rootEl.classList.add('vh-prelayout','vh-mask');
}
function unlockVisual(rootEl){
if (!rootEl) return;
rootEl.style.removeProperty('opacity');
rootEl.style.removeProperty('visibility');
rootEl.style.removeProperty('pointer-events');
rootEl.classList.remove('vh-mask','vh-prelayout');
}
async function buildSplide(){
const rootEl=getRoot();
if(!rootEl || !window.Splide) return;
if(rebuilding) return;
rebuilding = true;
lockVisual(rootEl);
detachBricksInstance(rootEl);
resetInline(rootEl);
ensureStructure(rootEl);
const opts = (()=>{
try{ return JSON.parse(rootEl.dataset.vh_splide_opts || '{}'); } catch(e){ return {}; }
})();
if(ownSplide){
try{ ownSplide.destroy(true); }catch(e){}
ownSplide=null;
}
ownSplide = new Splide(rootEl, opts);
ownSplide.mount();
// stabilizare într-un frame înainte să-l arătăm
await new Promise(r=>requestAnimationFrame(()=>r()));
ownSplide.refresh();
ownSplide.emit && ownSplide.emit('resize');
unlockVisual(rootEl);
if(!window.bricksData) window.bricksData = {};
if(!window.bricksData.splideInstances) window.bricksData.splideInstances = {};
window.bricksData.splideInstances[SPLIDE_ROOT_ID + '__own'] = ownSplide;
rebuilding = false;
}
// debounce rebuild cu token, ca să nu dăm rebuild de 2 ori
let rebuildToken = 0;
let rebuildTimerRef = null;
function rebuildSplideDebounced(delay=100){
const myToken = ++rebuildToken;
if(rebuildTimerRef) clearTimeout(rebuildTimerRef);
rebuildTimerRef = setTimeout(()=>{
if(myToken !== rebuildToken) return;
buildSplide();
}, delay);
}
// ====== Variation click (schimbă variantă + UI card) ======
function onClickVariation(e){
const item=e.target.closest && e.target.closest('[data-variation-item][data-variation-id]');
if(!item) return;
const a=e.target.closest('a');
if(a && item.contains(a)) e.preventDefault();
const card=item.closest('[data-product-card]');
if(!card || isClone(card)) return;
const vid=item.getAttribute('data-variation-id');
setActiveItem(card,item);
const data=variationCache.get(vid);
if(data!==undefined){
updateDiscountBox(card,data);
updateStockBox(card,data);
updateDimensions(card,data);
updatePrices(card,data);
} else {
fetchVariationData(vid,0).then(d=>{
variationCache.set(vid,d);
updateDiscountBox(card,d);
updateStockBox(card,d);
updateDimensions(card,d);
updatePrices(card,d);
}).catch(()=>{
variationCache.set(vid,null);
});
// prefetch pentru restul variantelor din același card
const siblings = Array.from(
card.querySelectorAll('[data-variation-item][data-variation-id]')
).map(el=>el.getAttribute('data-variation-id'));
prefetchIds(new Set(siblings));
}
const fullUrl=getFullUrlFromItem(item);
if(fullUrl) setMainImage(card, fullUrl);
}
function attachHoverPrefetch(){
if(!HOVER_PREFETCH) return;
if(document.body.dataset.vhHoverBound==='1') return;
document.body.dataset.vhHoverBound='1';
document.addEventListener('mouseenter', e=>{
const it = e.target.closest && e.target.closest('[data-variation-item][data-variation-id]');
if(!it) return;
const vid = it.getAttribute('data-variation-id');
if(vid && !variationCache.has(vid)){
prefetchIds(new Set([vid]));
}
}, true);
}
// ====== Filter & observer ======
// stare doar pt sliderul ăsta
let awaitingDom = false;
let awaitingFallback= null;
let mo = null;
function attachFilterWatcher(){
const sel=document.getElementById(FILTER_SELECT_ID);
if(!sel || sel.dataset.vhBound==='1') return;
sel.dataset.vhBound='1';
sel.addEventListener('change', ()=>{
const rootEl=getRoot();
if(rootEl) lockVisual(rootEl); // ascundem sliderul vechi instant
awaitingDom = true; // așteptăm noul DOM după filtrare
// fallback dacă Bricks reordonează fără să schimbe nodurile într-un mod care declanșează observerul
if(awaitingFallback) clearTimeout(awaitingFallback);
awaitingFallback = setTimeout(()=>{
if(awaitingDom){
awaitingDom = false;
rebuildSplideDebounced(0);
}
}, 900);
// refacem cardurile după ce Bricks a actualizat conținutul intern
setTimeout(async ()=>{
const root=getRoot();
if(root){
const cont = root.querySelector('.splide__list') || root;
await prefetchAllIn(cont);
initAllCards(document);
}
}, 30);
});
}
function startObserver(){
if(mo) return;
mo=new MutationObserver((mut)=>{
const rootEl = getRoot();
if(!rootEl) return;
let touch = false;
let addedRoot = null;
for(const m of mut){
if(m.type!=='childList') continue;
// verificăm DOAR mutații care ating sliderul ăsta
m.addedNodes && m.addedNodes.forEach(n=>{
if(n.nodeType!==1) return;
// 1) dacă nodul adăugat ESTE chiar root-ul meu
if(n === rootEl){
touch=true;
addedRoot=rootEl;
return;
}
// 2) dacă nodul adăugat CONȚINE root-ul meu
if(n.contains && n.contains(rootEl)){
touch=true;
addedRoot=rootEl;
return;
}
// 3) dacă root-ul meu conține nodul adăugat (s-a schimbat conținutul intern al sliderului meu)
if(rootEl.contains(n)){
touch=true;
addedRoot=rootEl;
return;
}
});
}
if(!touch) return; // ignora mutațiile altor slider-e
// Am detectat modificare relevantă PENTRU sliderul acesta
const activeRoot = addedRoot || rootEl;
if(activeRoot) lockVisual(activeRoot); // îl ascundem până terminăm rebuild
if(awaitingDom){
// era un refresh de filtrare pentru sliderul ăsta
awaitingDom = false;
if(awaitingFallback){
clearTimeout(awaitingFallback);
awaitingFallback=null;
}
rebuildSplideDebounced(60); // rebuild rapid pt sliderul ăsta
} else {
// doar o mică mutație (ex. resize/reflow etc.)
rebuildSplideDebounced(100);
}
// re-init la carduri după ce DOM-ul nou e acolo
setTimeout(()=>initAllCards(document), 20);
});
// Observăm tot body-ul, dar în callback filtrăm strict pe root-ul ăsta
mo.observe(document.body,{childList:true,subtree:true});
}
// ====== ENTRY POINT ======
onReady(async function(){
const root0 = getRoot();
if (root0) await prefetchAllIn(root0);
initAllCards(document);
if(!document.body.dataset.vhClickBound){
document.addEventListener('click', onClickVariation);
document.body.dataset.vhClickBound='1';
}
attachHoverPrefetch();
attachFilterWatcher();
startObserver();
if(root0){
const opts = readBricksOptions(root0);
root0.style.setProperty('--vh-gap', (opts.gap || '1.3vw'));
if (opts.fixedHeight) root0.style.setProperty('--vh-minh', opts.fixedHeight);
}
buildSplide();
window.addEventListener('resize', ()=>{
rebuildSplideDebounced(100);
}, {passive:true});
});
})();
</script>
asf
Canapea
In stoc
L
90cm
I
90cm
A
90cm
976 RON
976 RON
Aplică codul SPEED20 pentru -20% reducere
<style>
/* Ascunde complet sliderul PÂNĂ e 100% montat (fără fade/blink) */
#brxe-akucji.vh-mask {
opacity: 0 !important;
visibility: hidden !important;
pointer-events: none !important;
}
/* Prelayout: imităm EXACT ce va face Splide după mount,
ca să nu existe schimbare vizuală la gap/înălțime */
#brxe-akucji.vh-prelayout .splide__list {
display: flex;
}
#brxe-akucji.vh-prelayout .splide__slide {
margin-right: var(--vh-gap, 1.3vw);
min-height: var(--vh-minh, 36rem);
}
</style>
<script>
(function(){
const SPLIDE_ROOT_ID = 'brxe-akucji'; // <-- schimbi pt instanța 2
const FILTER_SELECT_ID = 'brxe-dsvvdo'; // <-- schimbi pt instanța 2
const PRICE_ANIMATIONS = false;
const HOVER_PREFETCH = true;
function onReady(fn){
if(document.readyState==='loading'){
document.addEventListener('DOMContentLoaded', fn,{once:true});
} else {
fn();
}
}
function getApiRoot(){
return (window.wpApiSettings && window.wpApiSettings.root) || '/wp-json/';
}
async function fetchVariationData(variationId, decimals){
const url = getApiRoot() + 'my/v1/variation-discount/' + encodeURIComponent(variationId) + '?decimals=' + (decimals ?? 0);
const res = await fetch(url, { credentials:'same-origin' });
if(!res.ok) throw new Error('HTTP '+res.status);
return res.json();
}
const forEach = (nl, cb)=> Array.prototype.forEach.call(nl, cb);
const isClone = el => !!el.closest('.splide__slide--clone');
function ensureShown(el){
if(el && getComputedStyle(el).display==='none'){
el.style.setProperty('display','flex','important');
}
}
function nfRON(val){
if(val==null||val==='') return '';
const n=Number(val);
if(!Number.isFinite(n)) return '';
return new Intl.NumberFormat('ro-RO',{minimumFractionDigits:0,maximumFractionDigits:2}).format(n)+' RON';
}
function stockTextRo(s){
return s==='instock'?'În stoc'
:s==='outofstock'?'Stoc epuizat'
:s==='onbackorder'?'În stoc furnizor'
:'';
}
function stockColor(s){
return s==='instock' ?'#00E832'
:s==='outofstock' ?'#FF0000'
:s==='onbackorder' ?'#ffb22e'
:'#9ca3af';
}
function formatDim(v,u){
if(v==null||v==='') return '';
return `${v}${u||''}`.trim();
}
function getFullUrlFromItem(item){
if(!item) return '';
const d=item.getAttribute('data-url'); if(d) return d;
const a=item.querySelector('a[href]'); if(a&&a.href) return a.href;
const img=item.querySelector('img'); if(img) return img.currentSrc||img.src||'';
return '';
}
const _barTimers=new WeakMap(), _hideTimers=new WeakMap();
function cancelOldBar(el){
const t=_barTimers.get(el);
if(t){clearTimeout(t);_barTimers.delete(el);}
}
function animateOldPriceBar(barEl){
if (!PRICE_ANIMATIONS || !barEl) return;
const t = barEl.style.transition;
if (!t || !/min-width/.test(t)){
barEl.style.transition = 'min-width .2s ease-in-out';
}
barEl.style.minWidth = '0%';
void barEl.offsetWidth;
barEl.style.minWidth = '110%';
}
function scheduleOldBar(el){
if(!PRICE_ANIMATIONS) return;
cancelOldBar(el);
const t=setTimeout(()=>{
animateOldPriceBar(el);
_barTimers.delete(el);
}, 0);
_barTimers.set(el,t);
}
function _scheduleHide(el,ms){
if(!PRICE_ANIMATIONS){
el.style.opacity=0;
return;
}
if(!el) return;
_cancelHide(el);
const t=setTimeout(()=>{
el.style.opacity=0;
_hideTimers.delete(el);
},ms);
_hideTimers.set(el,t);
}
function _cancelHide(el){
const t=_hideTimers.get(el);
if(t){clearTimeout(t);_hideTimers.delete(el);}
}
function hideOldPrice(el,delay){
if(!el) return;
if(PRICE_ANIMATIONS && delay>0){
_scheduleHide(el,delay);
} else {
_cancelHide(el);
el.style.opacity=0;
}
}
function showOldPrice(el){
if(!el) return;
_cancelHide(el);
ensureShown(el);
el.style.opacity=1;
}
function updateDiscountBox(card,p){
const box=card.querySelector('.reducere-produs-shop');
const text=card.querySelector('.text-reducere-produs-shop');
if(!box||!text) return;
if(!p||p.discount_percent==null){
box.style.opacity=0;
return;
}
const v='-'+p.discount_percent+'%';
if(text.textContent!==v) text.textContent=v;
ensureShown(box);
box.style.opacity=1;
}
function updateStockBox(card,p){
const wrap=card.querySelector('.stoc-produs-shop');
const dot=card.querySelector('.punct-stoc-produs-shop');
const txt=card.querySelector('.text-stoc-produs-shop');
if(!wrap||!dot||!txt) return;
const status=p&&p.stock_status?String(p.stock_status):'';
const label=stockTextRo(status);
if(!label){
wrap.classList.remove('is-visible');
if(txt.textContent) txt.textContent='';
return;
}
if(txt.textContent!==label) txt.textContent=label;
const c=stockColor(status);
if(dot.style.backgroundColor!==c) dot.style.backgroundColor=c;
ensureShown(wrap);
wrap.classList.add('is-visible');
}
function updateDimensions(card,p){
const l=card.querySelector('.text-lungime-produs-shop');
const w=card.querySelector('.text-adancime-produs-shop');
const h=card.querySelector('.text-inaltime-produs-shop');
if(!l && !w && !h) return;
const unit=p&&p.dimension_unit?String(p.dimension_unit):'';
const L=p?p.length:null, W=p?p.width:null, H=p?p.height:null;
if(l){ const v=formatDim(L,unit); if(l.textContent!==v) l.textContent=v; }
if(w){ const v=formatDim(W,unit); if(w.textContent!==v) w.textContent=v; }
if(h){ const v=formatDim(H,unit); if(h.textContent!==v) h.textContent=v; }
}
function updatePrices(card,p){
const actual=card.querySelector('.pret-actual-produs-shop');
const oldWrap=card.querySelector('.wrap-pret-vechi-produs-shop');
const oldText=card.querySelector('.pret-vechi-produs-shop');
const oldBar =card.querySelector('.div-pret-vechi-produs-shop');
if(!actual) return;
const reg = p && p.regular_price!=null ? p.regular_price : null;
const sale= p && p.sale_price !=null ? p.sale_price : null;
// niciun preț valid
if(reg==null && sale==null){
if(actual.textContent) actual.textContent='';
if(oldWrap) hideOldPrice(oldWrap,0);
if(oldBar){
cancelOldBar(oldBar);
oldBar.style.minWidth='0%';
}
if(oldText&&oldText.textContent) oldText.textContent='';
return;
}
// există reducere reală
if(sale!=null && reg!=null && +sale>0 && +reg>0 && +sale<+reg){
const cur=nfRON(sale);
if(actual.textContent!==cur) actual.textContent=cur;
if(oldWrap) showOldPrice(oldWrap);
const regTxt=nfRON(reg);
if(oldText && oldText.textContent!==regTxt) oldText.textContent=regTxt;
if(oldBar){
cancelOldBar(oldBar);
if (PRICE_ANIMATIONS) {
scheduleOldBar(oldBar);
} else {
// fără animații -> fă bara vizibilă din nou
oldBar.style.minWidth = '110%';
}
}
return;
}
// fără reducere -> afișăm doar prețul normal și ascundem bara veche
const cur=nfRON(reg!=null?reg:sale);
if(actual.textContent!==cur) actual.textContent=cur;
if(oldBar){
cancelOldBar(oldBar);
oldBar.style.minWidth='0%';
}
if(oldWrap){
hideOldPrice(oldWrap, PRICE_ANIMATIONS ? 200 : 0);
}
}
function setMainImage(card, url){
const main=card.querySelector('[data-main-image]');
if(!main||!url) return;
if(main.dataset.mainSrc===url) return;
const pre=new Image();
pre.onload=function(){
if(main.dataset.mainSrc===url) return;
if(main.tagName==='IMG'){
main.setAttribute('src',url);
} else {
main.style.backgroundImage='url("'+url+'")';
}
main.dataset.mainSrc=url;
};
pre.src=url;
}
function setActiveItem(card, active){
forEach(card.querySelectorAll('[data-variation-item]'), el=>{
const act=el===active;
el.classList.toggle('is-active',act);
el.setAttribute('aria-selected', act?'true':'false');
});
}
const variationCache=new Map();
const prefetchQueue=new Set();
async function prefetchIds(ids){
const tasks=[];
ids.forEach(id=>{
if(!id) return;
if(!variationCache.has(id) && !prefetchQueue.has(id)){
prefetchQueue.add(id);
tasks.push(
fetchVariationData(id,0)
.then(d=>variationCache.set(id,d))
.catch(()=>variationCache.set(id,null))
.finally(()=>prefetchQueue.delete(id))
);
}
});
if(tasks.length) await Promise.allSettled(tasks);
}
async function prefetchAllIn(container){
const ids=new Set(
Array.from(container.querySelectorAll('[data-variation-item][data-variation-id]'))
.filter(el=>!isClone(el))
.map(el=>el.getAttribute('data-variation-id'))
.filter(Boolean)
);
await prefetchIds(ids);
}
async function initCard(card){
if(!card || card.dataset.init==='1') return;
if(isClone(card)) return;
card.dataset.init='1';
const firstItem=card.querySelector('[data-variation-item][data-variation-id]');
if(!firstItem) return;
setActiveItem(card, firstItem);
const vid=firstItem.getAttribute('data-variation-id');
const cached=variationCache.get(vid);
if(cached!==undefined){
updateDiscountBox(card,cached);
updateStockBox(card,cached);
updateDimensions(card,cached);
updatePrices(card,cached);
} else {
try{
const data=await fetchVariationData(vid,0);
variationCache.set(vid,data);
updateDiscountBox(card,data);
updateStockBox(card,data);
updateDimensions(card,data);
updatePrices(card,data);
}catch(e){
variationCache.set(vid, null);
}
}
const firstUrl=getFullUrlFromItem(firstItem);
if(firstUrl) setMainImage(card, firstUrl);
}
function initAllCards(root){
forEach((root||document).querySelectorAll('[data-product-card]'), card=>initCard(card));
}
// ==== SPLIDE MANAGER PER INSTANȚĂ ====
let ownSplide=null;
let rebuilding=false;
function getRoot(){
return document.getElementById(SPLIDE_ROOT_ID);
}
function readBricksOptions(rootEl){
try{
const raw=rootEl.getAttribute('data-splide');
if(!raw) return {};
const opts=JSON.parse(raw);
return Object.assign({ type:'slide', speed:400, perPage:4, gap:'1.3vw', autoHeight:false }, opts);
}catch(e){
return { type:'slide', gap:'1.3vw', autoHeight:false };
}
}
function detachBricksInstance(rootEl){
if(!rootEl) return;
const map = (window.bricksData && window.bricksData.splideInstances) || null;
if(map){
for(const k of Object.keys(map)){
const inst = map[k];
if(inst && (inst.root===rootEl || inst.root?.id===rootEl.id)){
try{ inst.destroy && inst.destroy(true); }catch(e){}
map[k]=null;
}
}
}
if(!rootEl.dataset.vh_splide_opts){
const opts = readBricksOptions(rootEl);
rootEl.dataset.vh_splide_opts = JSON.stringify(opts);
}
rootEl.removeAttribute('data-splide');
rootEl.classList.add('vh-splide-locked');
}
function resetInline(rootEl){
const track=rootEl.querySelector('.splide__track');
const list =rootEl.querySelector('.splide__list');
const slides=rootEl.querySelectorAll('.splide__slide');
if(track){ track.style.height=''; track.style.transform=''; }
if(list ){ list.style.height=''; list.style.transform=''; list.style.gap=''; }
slides.forEach(sl=>{
sl.style.height='';
sl.style.minHeight='';
sl.style.margin='';
});
}
function ensureStructure(rootEl){
let track = rootEl.querySelector('.splide__track');
let list = rootEl.querySelector('.splide__list');
if(!track){
track = document.createElement('div');
track.className='splide__track';
while(rootEl.firstChild) track.appendChild(rootEl.firstChild);
rootEl.appendChild(track);
}
if(!list){
list = document.createElement('ul');
list.className='splide__list';
const children = Array.from(track.children);
children.forEach(ch=>{
const li=document.createElement('li');
li.className='splide__slide';
li.appendChild(ch);
list.appendChild(li);
});
track.innerHTML='';
track.appendChild(list);
}
const kids = Array.from(list.children);
kids.forEach(li=>{
if(!li.classList.contains('splide__slide')){
li.classList.add('splide__slide');
}
});
list.querySelectorAll('.splide__slide--clone').forEach(c=>c.remove());
return {track, list};
}
function lockVisual(rootEl){
if (!rootEl) return;
const opts = (()=>{
try{ return JSON.parse(rootEl.dataset.vh_splide_opts || '{}'); } catch(e){ return {}; }
})();
rootEl.style.setProperty('--vh-gap', (opts.gap || '1.3vw'));
if (opts.fixedHeight) rootEl.style.setProperty('--vh-minh', opts.fixedHeight);
// ascundem până terminăm rebuild-ul
rootEl.style.setProperty('opacity', '0', 'important');
rootEl.style.setProperty('visibility', 'hidden', 'important');
rootEl.style.setProperty('pointer-events', 'none', 'important');
rootEl.classList.add('vh-prelayout','vh-mask');
}
function unlockVisual(rootEl){
if (!rootEl) return;
rootEl.style.removeProperty('opacity');
rootEl.style.removeProperty('visibility');
rootEl.style.removeProperty('pointer-events');
rootEl.classList.remove('vh-mask','vh-prelayout');
}
async function buildSplide(){
const rootEl=getRoot();
if(!rootEl || !window.Splide) return;
if(rebuilding) return;
rebuilding = true;
lockVisual(rootEl);
detachBricksInstance(rootEl);
resetInline(rootEl);
ensureStructure(rootEl);
const opts = (()=>{
try{ return JSON.parse(rootEl.dataset.vh_splide_opts || '{}'); } catch(e){ return {}; }
})();
if(ownSplide){
try{ ownSplide.destroy(true); }catch(e){}
ownSplide=null;
}
ownSplide = new Splide(rootEl, opts);
ownSplide.mount();
// stabilizare într-un frame înainte să-l arătăm
await new Promise(r=>requestAnimationFrame(()=>r()));
ownSplide.refresh();
ownSplide.emit && ownSplide.emit('resize');
unlockVisual(rootEl);
if(!window.bricksData) window.bricksData = {};
if(!window.bricksData.splideInstances) window.bricksData.splideInstances = {};
window.bricksData.splideInstances[SPLIDE_ROOT_ID + '__own'] = ownSplide;
rebuilding = false;
}
// debounce rebuild cu token, ca să nu dăm rebuild de 2 ori
let rebuildToken = 0;
let rebuildTimerRef = null;
function rebuildSplideDebounced(delay=100){
const myToken = ++rebuildToken;
if(rebuildTimerRef) clearTimeout(rebuildTimerRef);
rebuildTimerRef = setTimeout(()=>{
if(myToken !== rebuildToken) return;
buildSplide();
}, delay);
}
// ====== Variation click (schimbă variantă + UI card) ======
function onClickVariation(e){
const item=e.target.closest && e.target.closest('[data-variation-item][data-variation-id]');
if(!item) return;
const a=e.target.closest('a');
if(a && item.contains(a)) e.preventDefault();
const card=item.closest('[data-product-card]');
if(!card || isClone(card)) return;
const vid=item.getAttribute('data-variation-id');
setActiveItem(card,item);
const data=variationCache.get(vid);
if(data!==undefined){
updateDiscountBox(card,data);
updateStockBox(card,data);
updateDimensions(card,data);
updatePrices(card,data);
} else {
fetchVariationData(vid,0).then(d=>{
variationCache.set(vid,d);
updateDiscountBox(card,d);
updateStockBox(card,d);
updateDimensions(card,d);
updatePrices(card,d);
}).catch(()=>{
variationCache.set(vid,null);
});
// prefetch pentru restul variantelor din același card
const siblings = Array.from(
card.querySelectorAll('[data-variation-item][data-variation-id]')
).map(el=>el.getAttribute('data-variation-id'));
prefetchIds(new Set(siblings));
}
const fullUrl=getFullUrlFromItem(item);
if(fullUrl) setMainImage(card, fullUrl);
}
function attachHoverPrefetch(){
if(!HOVER_PREFETCH) return;
if(document.body.dataset.vhHoverBound==='1') return;
document.body.dataset.vhHoverBound='1';
document.addEventListener('mouseenter', e=>{
const it = e.target.closest && e.target.closest('[data-variation-item][data-variation-id]');
if(!it) return;
const vid = it.getAttribute('data-variation-id');
if(vid && !variationCache.has(vid)){
prefetchIds(new Set([vid]));
}
}, true);
}
// ====== Filter & observer ======
// stare doar pt sliderul ăsta
let awaitingDom = false;
let awaitingFallback= null;
let mo = null;
function attachFilterWatcher(){
const sel=document.getElementById(FILTER_SELECT_ID);
if(!sel || sel.dataset.vhBound==='1') return;
sel.dataset.vhBound='1';
sel.addEventListener('change', ()=>{
const rootEl=getRoot();
if(rootEl) lockVisual(rootEl); // ascundem sliderul vechi instant
awaitingDom = true; // așteptăm noul DOM după filtrare
// fallback dacă Bricks reordonează fără să schimbe nodurile într-un mod care declanșează observerul
if(awaitingFallback) clearTimeout(awaitingFallback);
awaitingFallback = setTimeout(()=>{
if(awaitingDom){
awaitingDom = false;
rebuildSplideDebounced(0);
}
}, 900);
// refacem cardurile după ce Bricks a actualizat conținutul intern
setTimeout(async ()=>{
const root=getRoot();
if(root){
const cont = root.querySelector('.splide__list') || root;
await prefetchAllIn(cont);
initAllCards(document);
}
}, 30);
});
}
function startObserver(){
if(mo) return;
mo=new MutationObserver((mut)=>{
const rootEl = getRoot();
if(!rootEl) return;
let touch = false;
let addedRoot = null;
for(const m of mut){
if(m.type!=='childList') continue;
// verificăm DOAR mutații care ating sliderul ăsta
m.addedNodes && m.addedNodes.forEach(n=>{
if(n.nodeType!==1) return;
// 1) dacă nodul adăugat ESTE chiar root-ul meu
if(n === rootEl){
touch=true;
addedRoot=rootEl;
return;
}
// 2) dacă nodul adăugat CONȚINE root-ul meu
if(n.contains && n.contains(rootEl)){
touch=true;
addedRoot=rootEl;
return;
}
// 3) dacă root-ul meu conține nodul adăugat (s-a schimbat conținutul intern al sliderului meu)
if(rootEl.contains(n)){
touch=true;
addedRoot=rootEl;
return;
}
});
}
if(!touch) return; // ignora mutațiile altor slider-e
// Am detectat modificare relevantă PENTRU sliderul acesta
const activeRoot = addedRoot || rootEl;
if(activeRoot) lockVisual(activeRoot); // îl ascundem până terminăm rebuild
if(awaitingDom){
// era un refresh de filtrare pentru sliderul ăsta
awaitingDom = false;
if(awaitingFallback){
clearTimeout(awaitingFallback);
awaitingFallback=null;
}
rebuildSplideDebounced(60); // rebuild rapid pt sliderul ăsta
} else {
// doar o mică mutație (ex. resize/reflow etc.)
rebuildSplideDebounced(100);
}
// re-init la carduri după ce DOM-ul nou e acolo
setTimeout(()=>initAllCards(document), 20);
});
// Observăm tot body-ul, dar în callback filtrăm strict pe root-ul ăsta
mo.observe(document.body,{childList:true,subtree:true});
}
// ====== ENTRY POINT ======
onReady(async function(){
const root0 = getRoot();
if (root0) await prefetchAllIn(root0);
initAllCards(document);
if(!document.body.dataset.vhClickBound){
document.addEventListener('click', onClickVariation);
document.body.dataset.vhClickBound='1';
}
attachHoverPrefetch();
attachFilterWatcher();
startObserver();
if(root0){
const opts = readBricksOptions(root0);
root0.style.setProperty('--vh-gap', (opts.gap || '1.3vw'));
if (opts.fixedHeight) root0.style.setProperty('--vh-minh', opts.fixedHeight);
}
buildSplide();
window.addEventListener('resize', ()=>{
rebuildSplideDebounced(100);
}, {passive:true});
});
})();
</script>
asf
L
90cm
I
90cm
A
90cm
976 RON
976 RON
Aplică codul SPEED20 pentru -20% reducere
<style>
/* Ascunde complet sliderul PÂNĂ e 100% montat (fără fade/blink) */
#brxe-akucji.vh-mask {
opacity: 0 !important;
visibility: hidden !important;
pointer-events: none !important;
}
/* Prelayout: imităm EXACT ce va face Splide după mount,
ca să nu existe schimbare vizuală la gap/înălțime */
#brxe-akucji.vh-prelayout .splide__list {
display: flex;
}
#brxe-akucji.vh-prelayout .splide__slide {
margin-right: var(--vh-gap, 1.3vw);
min-height: var(--vh-minh, 36rem);
}
</style>
<script>
(function(){
const SPLIDE_ROOT_ID = 'brxe-akucji'; // <-- schimbi pt instanța 2
const FILTER_SELECT_ID = 'brxe-dsvvdo'; // <-- schimbi pt instanța 2
const PRICE_ANIMATIONS = false;
const HOVER_PREFETCH = true;
function onReady(fn){
if(document.readyState==='loading'){
document.addEventListener('DOMContentLoaded', fn,{once:true});
} else {
fn();
}
}
function getApiRoot(){
return (window.wpApiSettings && window.wpApiSettings.root) || '/wp-json/';
}
async function fetchVariationData(variationId, decimals){
const url = getApiRoot() + 'my/v1/variation-discount/' + encodeURIComponent(variationId) + '?decimals=' + (decimals ?? 0);
const res = await fetch(url, { credentials:'same-origin' });
if(!res.ok) throw new Error('HTTP '+res.status);
return res.json();
}
const forEach = (nl, cb)=> Array.prototype.forEach.call(nl, cb);
const isClone = el => !!el.closest('.splide__slide--clone');
function ensureShown(el){
if(el && getComputedStyle(el).display==='none'){
el.style.setProperty('display','flex','important');
}
}
function nfRON(val){
if(val==null||val==='') return '';
const n=Number(val);
if(!Number.isFinite(n)) return '';
return new Intl.NumberFormat('ro-RO',{minimumFractionDigits:0,maximumFractionDigits:2}).format(n)+' RON';
}
function stockTextRo(s){
return s==='instock'?'În stoc'
:s==='outofstock'?'Stoc epuizat'
:s==='onbackorder'?'În stoc furnizor'
:'';
}
function stockColor(s){
return s==='instock' ?'#00E832'
:s==='outofstock' ?'#FF0000'
:s==='onbackorder' ?'#ffb22e'
:'#9ca3af';
}
function formatDim(v,u){
if(v==null||v==='') return '';
return `${v}${u||''}`.trim();
}
function getFullUrlFromItem(item){
if(!item) return '';
const d=item.getAttribute('data-url'); if(d) return d;
const a=item.querySelector('a[href]'); if(a&&a.href) return a.href;
const img=item.querySelector('img'); if(img) return img.currentSrc||img.src||'';
return '';
}
const _barTimers=new WeakMap(), _hideTimers=new WeakMap();
function cancelOldBar(el){
const t=_barTimers.get(el);
if(t){clearTimeout(t);_barTimers.delete(el);}
}
function animateOldPriceBar(barEl){
if (!PRICE_ANIMATIONS || !barEl) return;
const t = barEl.style.transition;
if (!t || !/min-width/.test(t)){
barEl.style.transition = 'min-width .2s ease-in-out';
}
barEl.style.minWidth = '0%';
void barEl.offsetWidth;
barEl.style.minWidth = '110%';
}
function scheduleOldBar(el){
if(!PRICE_ANIMATIONS) return;
cancelOldBar(el);
const t=setTimeout(()=>{
animateOldPriceBar(el);
_barTimers.delete(el);
}, 0);
_barTimers.set(el,t);
}
function _scheduleHide(el,ms){
if(!PRICE_ANIMATIONS){
el.style.opacity=0;
return;
}
if(!el) return;
_cancelHide(el);
const t=setTimeout(()=>{
el.style.opacity=0;
_hideTimers.delete(el);
},ms);
_hideTimers.set(el,t);
}
function _cancelHide(el){
const t=_hideTimers.get(el);
if(t){clearTimeout(t);_hideTimers.delete(el);}
}
function hideOldPrice(el,delay){
if(!el) return;
if(PRICE_ANIMATIONS && delay>0){
_scheduleHide(el,delay);
} else {
_cancelHide(el);
el.style.opacity=0;
}
}
function showOldPrice(el){
if(!el) return;
_cancelHide(el);
ensureShown(el);
el.style.opacity=1;
}
function updateDiscountBox(card,p){
const box=card.querySelector('.reducere-produs-shop');
const text=card.querySelector('.text-reducere-produs-shop');
if(!box||!text) return;
if(!p||p.discount_percent==null){
box.style.opacity=0;
return;
}
const v='-'+p.discount_percent+'%';
if(text.textContent!==v) text.textContent=v;
ensureShown(box);
box.style.opacity=1;
}
function updateStockBox(card,p){
const wrap=card.querySelector('.stoc-produs-shop');
const dot=card.querySelector('.punct-stoc-produs-shop');
const txt=card.querySelector('.text-stoc-produs-shop');
if(!wrap||!dot||!txt) return;
const status=p&&p.stock_status?String(p.stock_status):'';
const label=stockTextRo(status);
if(!label){
wrap.classList.remove('is-visible');
if(txt.textContent) txt.textContent='';
return;
}
if(txt.textContent!==label) txt.textContent=label;
const c=stockColor(status);
if(dot.style.backgroundColor!==c) dot.style.backgroundColor=c;
ensureShown(wrap);
wrap.classList.add('is-visible');
}
function updateDimensions(card,p){
const l=card.querySelector('.text-lungime-produs-shop');
const w=card.querySelector('.text-adancime-produs-shop');
const h=card.querySelector('.text-inaltime-produs-shop');
if(!l && !w && !h) return;
const unit=p&&p.dimension_unit?String(p.dimension_unit):'';
const L=p?p.length:null, W=p?p.width:null, H=p?p.height:null;
if(l){ const v=formatDim(L,unit); if(l.textContent!==v) l.textContent=v; }
if(w){ const v=formatDim(W,unit); if(w.textContent!==v) w.textContent=v; }
if(h){ const v=formatDim(H,unit); if(h.textContent!==v) h.textContent=v; }
}
function updatePrices(card,p){
const actual=card.querySelector('.pret-actual-produs-shop');
const oldWrap=card.querySelector('.wrap-pret-vechi-produs-shop');
const oldText=card.querySelector('.pret-vechi-produs-shop');
const oldBar =card.querySelector('.div-pret-vechi-produs-shop');
if(!actual) return;
const reg = p && p.regular_price!=null ? p.regular_price : null;
const sale= p && p.sale_price !=null ? p.sale_price : null;
// niciun preț valid
if(reg==null && sale==null){
if(actual.textContent) actual.textContent='';
if(oldWrap) hideOldPrice(oldWrap,0);
if(oldBar){
cancelOldBar(oldBar);
oldBar.style.minWidth='0%';
}
if(oldText&&oldText.textContent) oldText.textContent='';
return;
}
// există reducere reală
if(sale!=null && reg!=null && +sale>0 && +reg>0 && +sale<+reg){
const cur=nfRON(sale);
if(actual.textContent!==cur) actual.textContent=cur;
if(oldWrap) showOldPrice(oldWrap);
const regTxt=nfRON(reg);
if(oldText && oldText.textContent!==regTxt) oldText.textContent=regTxt;
if(oldBar){
cancelOldBar(oldBar);
if (PRICE_ANIMATIONS) {
scheduleOldBar(oldBar);
} else {
// fără animații -> fă bara vizibilă din nou
oldBar.style.minWidth = '110%';
}
}
return;
}
// fără reducere -> afișăm doar prețul normal și ascundem bara veche
const cur=nfRON(reg!=null?reg:sale);
if(actual.textContent!==cur) actual.textContent=cur;
if(oldBar){
cancelOldBar(oldBar);
oldBar.style.minWidth='0%';
}
if(oldWrap){
hideOldPrice(oldWrap, PRICE_ANIMATIONS ? 200 : 0);
}
}
function setMainImage(card, url){
const main=card.querySelector('[data-main-image]');
if(!main||!url) return;
if(main.dataset.mainSrc===url) return;
const pre=new Image();
pre.onload=function(){
if(main.dataset.mainSrc===url) return;
if(main.tagName==='IMG'){
main.setAttribute('src',url);
} else {
main.style.backgroundImage='url("'+url+'")';
}
main.dataset.mainSrc=url;
};
pre.src=url;
}
function setActiveItem(card, active){
forEach(card.querySelectorAll('[data-variation-item]'), el=>{
const act=el===active;
el.classList.toggle('is-active',act);
el.setAttribute('aria-selected', act?'true':'false');
});
}
const variationCache=new Map();
const prefetchQueue=new Set();
async function prefetchIds(ids){
const tasks=[];
ids.forEach(id=>{
if(!id) return;
if(!variationCache.has(id) && !prefetchQueue.has(id)){
prefetchQueue.add(id);
tasks.push(
fetchVariationData(id,0)
.then(d=>variationCache.set(id,d))
.catch(()=>variationCache.set(id,null))
.finally(()=>prefetchQueue.delete(id))
);
}
});
if(tasks.length) await Promise.allSettled(tasks);
}
async function prefetchAllIn(container){
const ids=new Set(
Array.from(container.querySelectorAll('[data-variation-item][data-variation-id]'))
.filter(el=>!isClone(el))
.map(el=>el.getAttribute('data-variation-id'))
.filter(Boolean)
);
await prefetchIds(ids);
}
async function initCard(card){
if(!card || card.dataset.init==='1') return;
if(isClone(card)) return;
card.dataset.init='1';
const firstItem=card.querySelector('[data-variation-item][data-variation-id]');
if(!firstItem) return;
setActiveItem(card, firstItem);
const vid=firstItem.getAttribute('data-variation-id');
const cached=variationCache.get(vid);
if(cached!==undefined){
updateDiscountBox(card,cached);
updateStockBox(card,cached);
updateDimensions(card,cached);
updatePrices(card,cached);
} else {
try{
const data=await fetchVariationData(vid,0);
variationCache.set(vid,data);
updateDiscountBox(card,data);
updateStockBox(card,data);
updateDimensions(card,data);
updatePrices(card,data);
}catch(e){
variationCache.set(vid, null);
}
}
const firstUrl=getFullUrlFromItem(firstItem);
if(firstUrl) setMainImage(card, firstUrl);
}
function initAllCards(root){
forEach((root||document).querySelectorAll('[data-product-card]'), card=>initCard(card));
}
// ==== SPLIDE MANAGER PER INSTANȚĂ ====
let ownSplide=null;
let rebuilding=false;
function getRoot(){
return document.getElementById(SPLIDE_ROOT_ID);
}
function readBricksOptions(rootEl){
try{
const raw=rootEl.getAttribute('data-splide');
if(!raw) return {};
const opts=JSON.parse(raw);
return Object.assign({ type:'slide', speed:400, perPage:4, gap:'1.3vw', autoHeight:false }, opts);
}catch(e){
return { type:'slide', gap:'1.3vw', autoHeight:false };
}
}
function detachBricksInstance(rootEl){
if(!rootEl) return;
const map = (window.bricksData && window.bricksData.splideInstances) || null;
if(map){
for(const k of Object.keys(map)){
const inst = map[k];
if(inst && (inst.root===rootEl || inst.root?.id===rootEl.id)){
try{ inst.destroy && inst.destroy(true); }catch(e){}
map[k]=null;
}
}
}
if(!rootEl.dataset.vh_splide_opts){
const opts = readBricksOptions(rootEl);
rootEl.dataset.vh_splide_opts = JSON.stringify(opts);
}
rootEl.removeAttribute('data-splide');
rootEl.classList.add('vh-splide-locked');
}
function resetInline(rootEl){
const track=rootEl.querySelector('.splide__track');
const list =rootEl.querySelector('.splide__list');
const slides=rootEl.querySelectorAll('.splide__slide');
if(track){ track.style.height=''; track.style.transform=''; }
if(list ){ list.style.height=''; list.style.transform=''; list.style.gap=''; }
slides.forEach(sl=>{
sl.style.height='';
sl.style.minHeight='';
sl.style.margin='';
});
}
function ensureStructure(rootEl){
let track = rootEl.querySelector('.splide__track');
let list = rootEl.querySelector('.splide__list');
if(!track){
track = document.createElement('div');
track.className='splide__track';
while(rootEl.firstChild) track.appendChild(rootEl.firstChild);
rootEl.appendChild(track);
}
if(!list){
list = document.createElement('ul');
list.className='splide__list';
const children = Array.from(track.children);
children.forEach(ch=>{
const li=document.createElement('li');
li.className='splide__slide';
li.appendChild(ch);
list.appendChild(li);
});
track.innerHTML='';
track.appendChild(list);
}
const kids = Array.from(list.children);
kids.forEach(li=>{
if(!li.classList.contains('splide__slide')){
li.classList.add('splide__slide');
}
});
list.querySelectorAll('.splide__slide--clone').forEach(c=>c.remove());
return {track, list};
}
function lockVisual(rootEl){
if (!rootEl) return;
const opts = (()=>{
try{ return JSON.parse(rootEl.dataset.vh_splide_opts || '{}'); } catch(e){ return {}; }
})();
rootEl.style.setProperty('--vh-gap', (opts.gap || '1.3vw'));
if (opts.fixedHeight) rootEl.style.setProperty('--vh-minh', opts.fixedHeight);
// ascundem până terminăm rebuild-ul
rootEl.style.setProperty('opacity', '0', 'important');
rootEl.style.setProperty('visibility', 'hidden', 'important');
rootEl.style.setProperty('pointer-events', 'none', 'important');
rootEl.classList.add('vh-prelayout','vh-mask');
}
function unlockVisual(rootEl){
if (!rootEl) return;
rootEl.style.removeProperty('opacity');
rootEl.style.removeProperty('visibility');
rootEl.style.removeProperty('pointer-events');
rootEl.classList.remove('vh-mask','vh-prelayout');
}
async function buildSplide(){
const rootEl=getRoot();
if(!rootEl || !window.Splide) return;
if(rebuilding) return;
rebuilding = true;
lockVisual(rootEl);
detachBricksInstance(rootEl);
resetInline(rootEl);
ensureStructure(rootEl);
const opts = (()=>{
try{ return JSON.parse(rootEl.dataset.vh_splide_opts || '{}'); } catch(e){ return {}; }
})();
if(ownSplide){
try{ ownSplide.destroy(true); }catch(e){}
ownSplide=null;
}
ownSplide = new Splide(rootEl, opts);
ownSplide.mount();
// stabilizare într-un frame înainte să-l arătăm
await new Promise(r=>requestAnimationFrame(()=>r()));
ownSplide.refresh();
ownSplide.emit && ownSplide.emit('resize');
unlockVisual(rootEl);
if(!window.bricksData) window.bricksData = {};
if(!window.bricksData.splideInstances) window.bricksData.splideInstances = {};
window.bricksData.splideInstances[SPLIDE_ROOT_ID + '__own'] = ownSplide;
rebuilding = false;
}
// debounce rebuild cu token, ca să nu dăm rebuild de 2 ori
let rebuildToken = 0;
let rebuildTimerRef = null;
function rebuildSplideDebounced(delay=100){
const myToken = ++rebuildToken;
if(rebuildTimerRef) clearTimeout(rebuildTimerRef);
rebuildTimerRef = setTimeout(()=>{
if(myToken !== rebuildToken) return;
buildSplide();
}, delay);
}
// ====== Variation click (schimbă variantă + UI card) ======
function onClickVariation(e){
const item=e.target.closest && e.target.closest('[data-variation-item][data-variation-id]');
if(!item) return;
const a=e.target.closest('a');
if(a && item.contains(a)) e.preventDefault();
const card=item.closest('[data-product-card]');
if(!card || isClone(card)) return;
const vid=item.getAttribute('data-variation-id');
setActiveItem(card,item);
const data=variationCache.get(vid);
if(data!==undefined){
updateDiscountBox(card,data);
updateStockBox(card,data);
updateDimensions(card,data);
updatePrices(card,data);
} else {
fetchVariationData(vid,0).then(d=>{
variationCache.set(vid,d);
updateDiscountBox(card,d);
updateStockBox(card,d);
updateDimensions(card,d);
updatePrices(card,d);
}).catch(()=>{
variationCache.set(vid,null);
});
// prefetch pentru restul variantelor din același card
const siblings = Array.from(
card.querySelectorAll('[data-variation-item][data-variation-id]')
).map(el=>el.getAttribute('data-variation-id'));
prefetchIds(new Set(siblings));
}
const fullUrl=getFullUrlFromItem(item);
if(fullUrl) setMainImage(card, fullUrl);
}
function attachHoverPrefetch(){
if(!HOVER_PREFETCH) return;
if(document.body.dataset.vhHoverBound==='1') return;
document.body.dataset.vhHoverBound='1';
document.addEventListener('mouseenter', e=>{
const it = e.target.closest && e.target.closest('[data-variation-item][data-variation-id]');
if(!it) return;
const vid = it.getAttribute('data-variation-id');
if(vid && !variationCache.has(vid)){
prefetchIds(new Set([vid]));
}
}, true);
}
// ====== Filter & observer ======
// stare doar pt sliderul ăsta
let awaitingDom = false;
let awaitingFallback= null;
let mo = null;
function attachFilterWatcher(){
const sel=document.getElementById(FILTER_SELECT_ID);
if(!sel || sel.dataset.vhBound==='1') return;
sel.dataset.vhBound='1';
sel.addEventListener('change', ()=>{
const rootEl=getRoot();
if(rootEl) lockVisual(rootEl); // ascundem sliderul vechi instant
awaitingDom = true; // așteptăm noul DOM după filtrare
// fallback dacă Bricks reordonează fără să schimbe nodurile într-un mod care declanșează observerul
if(awaitingFallback) clearTimeout(awaitingFallback);
awaitingFallback = setTimeout(()=>{
if(awaitingDom){
awaitingDom = false;
rebuildSplideDebounced(0);
}
}, 900);
// refacem cardurile după ce Bricks a actualizat conținutul intern
setTimeout(async ()=>{
const root=getRoot();
if(root){
const cont = root.querySelector('.splide__list') || root;
await prefetchAllIn(cont);
initAllCards(document);
}
}, 30);
});
}
function startObserver(){
if(mo) return;
mo=new MutationObserver((mut)=>{
const rootEl = getRoot();
if(!rootEl) return;
let touch = false;
let addedRoot = null;
for(const m of mut){
if(m.type!=='childList') continue;
// verificăm DOAR mutații care ating sliderul ăsta
m.addedNodes && m.addedNodes.forEach(n=>{
if(n.nodeType!==1) return;
// 1) dacă nodul adăugat ESTE chiar root-ul meu
if(n === rootEl){
touch=true;
addedRoot=rootEl;
return;
}
// 2) dacă nodul adăugat CONȚINE root-ul meu
if(n.contains && n.contains(rootEl)){
touch=true;
addedRoot=rootEl;
return;
}
// 3) dacă root-ul meu conține nodul adăugat (s-a schimbat conținutul intern al sliderului meu)
if(rootEl.contains(n)){
touch=true;
addedRoot=rootEl;
return;
}
});
}
if(!touch) return; // ignora mutațiile altor slider-e
// Am detectat modificare relevantă PENTRU sliderul acesta
const activeRoot = addedRoot || rootEl;
if(activeRoot) lockVisual(activeRoot); // îl ascundem până terminăm rebuild
if(awaitingDom){
// era un refresh de filtrare pentru sliderul ăsta
awaitingDom = false;
if(awaitingFallback){
clearTimeout(awaitingFallback);
awaitingFallback=null;
}
rebuildSplideDebounced(60); // rebuild rapid pt sliderul ăsta
} else {
// doar o mică mutație (ex. resize/reflow etc.)
rebuildSplideDebounced(100);
}
// re-init la carduri după ce DOM-ul nou e acolo
setTimeout(()=>initAllCards(document), 20);
});
// Observăm tot body-ul, dar în callback filtrăm strict pe root-ul ăsta
mo.observe(document.body,{childList:true,subtree:true});
}
// ====== ENTRY POINT ======
onReady(async function(){
const root0 = getRoot();
if (root0) await prefetchAllIn(root0);
initAllCards(document);
if(!document.body.dataset.vhClickBound){
document.addEventListener('click', onClickVariation);
document.body.dataset.vhClickBound='1';
}
attachHoverPrefetch();
attachFilterWatcher();
startObserver();
if(root0){
const opts = readBricksOptions(root0);
root0.style.setProperty('--vh-gap', (opts.gap || '1.3vw'));
if (opts.fixedHeight) root0.style.setProperty('--vh-minh', opts.fixedHeight);
}
buildSplide();
window.addEventListener('resize', ()=>{
rebuildSplideDebounced(100);
}, {passive:true});
});
})();
</script>
asf
L
90cm
I
90cm
A
90cm
976 RON
976 RON
Plătește produsele în rate
Bucură-te de ofertele noastre
BRD
3-5 Rate Disponibile

Raiffeisen
9-12 Rate Disponibile

O rețea de parteneri formata cu gândul la tine
Cumpără cu încredere la SpeedCasa
DE LA CASĂ LA ACASĂ
Descoperă procesul SpeedCasa și dă start
amenajării tale de vis
“I love your build because you made it for people like us who don't know what we're doing. It just works.”
“I love your build because you made it for people like us who don't know what we're doing. It just works. “I love your build because you made it for people like us who don't know what we're doing. It just works. “
Andrei Grigorescu
Fondator Numele Firmei
“I love your build because you made it for people like us who don't know what we're doing. It just works.”
“I love your build because you made it for people like us who don't know what we're doing. It just works. “I love your build because you made it for people like us who don't know what we're doing. It just works. “
Andrei Grigorescu
Fondator Numele Firmei
“I love your build because you made it for people like us who don't know what we're doing. It just works.”
“I love your build because you made it for people like us who don't know what we're doing. It just works. “I love your build because you made it for people like us who don't know what we're doing. It just works. “
Andrei Grigorescu
Fondator Numele Firmei
“I love your build because you made it for people like us who don't know what we're doing. It just works.”
“I love your build because you made it for people like us who don't know what we're doing. It just works. “I love your build because you made it for people like us who don't know what we're doing. It just works. “
Andrei Grigorescu
Fondator Numele Firmei
DE LA CASĂ LA ACASĂ
Prima platforma online design interior din Romania

“I love your build because you made it for people like us who don't know what we're doing. It just works. I love your build because you made it for people like us who don't know what we're doing. It just works.”
Andrei A.
4 Camere, Pachet Redecorare

“I love your build because you made it for people like us who don't know what we're doing. It just works. I love your build because you made it for people like us who don't know what we're doing. It just works.”
Andrei A.
4 Camere, Pachet Redecorare

“I love your build because you made it for people like us who don't know what we're doing. It just works. I love your build because you made it for people like us who don't know what we're doing. It just works.”
Andrei A.
4 Camere, Pachet Redecorare

“I love your build because you made it for people like us who don't know what we're doing. It just works. I love your build because you made it for people like us who don't know what we're doing. It just works.”
Andrei A.
4 Camere, Pachet Redecorare
Categorii produse
Mobilier
Placări Pereți
Produse Ceramică
Paturi
Placări Pereți
Produse Ceramică
Dulap
Categorii produse
Mobilier
Placări Pereți
Produse Ceramică
Paturi
Placări Pereți
Produse Ceramică
Categorii produse
Mobilier
Placări Pereți
Produse Ceramică
Paturi
Placări Pereți
Inspirație, oferte speciale
și multe beneficii pentru tine
Alătură-te comunității Speed gratuit și bucură-te de avantajele primei platforme digitale de design interior din Europa.
I want to receive a newsletter on promotions, sales and other marketing information from Tylko S.A. to the indicated e-mail address. I can withdraw my consent at any time, but this will not affect the legality of the processing that took place before its withdrawal.
CUM FUNCȚIONEAZĂ
PLATFORMA SPEEDCASA?
Alătură-te comunității Speed gratuit și bucură-te de avantajele primei platforme digitale de design interior din Europa.

Avantaj Speed

Avantaj Speed

Avantaj Speed

Avantaj Speed
TIMP DE VIZUALIZARE - 5 MINUTE
CUM SĂ FOLOSEȘTI CONFIGURATORUL SPEED?
DISCOUNTURILE SPEED
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
-10% LA ORICE PRODUS
ISRA X SHIFT
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
Avantaj Parteneriat
Avantaj Parteneriat
Avantaj Parteneriat
Avantaj Parteneriat
DESCOPERĂ povestea speedcasa










Politica Cookie
Politica de retur
Termeni și condiții
Politica gdpr
Made by SHIFT








