<div x-data="{ expanded: false }" class="border-b border-neutral-200 md:pb-3 text-neutral-800 text-neutral-800">
<h2 class="font-medium py-4 md:pt-6 md:pb-3 text-base md:text-xl">
<button type="button" @click="expanded = !expanded " class="flex justify-between items-center w-full ">
<span class="flex flex-wrap gap-3">
Accordion title
</span>
<span :class="expanded ? 'rotate-180' : ''" class="transform transition-transform duration-300">
<svg class=" shrink-0" width="32" height="32" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.5303 14.5303C12.2374 14.8232 11.7626 14.8232 11.4697 14.5303L7.46967 10.5303C7.17678 10.2374 7.17678 9.76256 7.46967 9.46967C7.76256 9.17678 8.23744 9.17678 8.53033 9.46967L12 12.9393L15.4697 9.46967C15.7626 9.17678 16.2374 9.17678 16.5303 9.46967C16.8232 9.76256 16.8232 10.2374 16.5303 10.5303L12.5303 14.5303Z" fill="currentColor" />
</svg>
</span>
</button>
</h2>
<div x-cloak x-show="expanded" x-collapse class=" ">
<div class="pb-4 md:pb-3">
<div x-data="rangeSlider" x-init="init(0, 1000, 200, 800)">
<div class="relative select-none touch-none mx-6 my-3 md:mx-0 h-0.5 bg-neutral-300" x-ref="slider">
<div class="absolute bg-dark-black h-full w-full" :style="'width:' + getWidth() + '; left:' + getMinPos()"></div>
<div class="absolute -ml-2 top-1/2 -translate-y-1/2 cursor-pointer rounded-full border-2 border-dark-black bg-light-white w-6 h-6 z-30 hover:bg-neutral-200" @touchstart="dragFrom=true" @mousedown="dragFrom=true" :style="'left:' + getFromPos()"></div>
<div class="absolute -ml-2 top-1/2 -translate-y-1/2 cursor-pointer rounded-full border-2 border-dark-black bg-light-white w-6 h-6 z-30 hover:bg-neutral-200" @touchstart="dragTo=true" @mousedown="dragTo=true" :style="'left:' + getToPos()"></div>
</div>
<div class="pt-2 flex justify-between select-none mt-2">
<label class="flex gap-1 justify-center items-center py-2 px-3 border border-neutral-300 cursor-text focus-within:ring-4 focus-within:ring-blue-200 rounded-md">
<div x-data="{value:from}" class="relative h-full">
<input class="text-center border-0 p-0 w-full absolute top-0 left-0 bg-transparent focus:border-none focus:ring-0" x-model="value" type="text" name="from" x-effect="value=Math.min(from, to)" @keyup.enter="triggerChange(value,'from')" @blur="triggerChange(value,'from')">
<span class="invisible block w-auto overflow-auto text-nowrap min-w-6 h-full" x-text="value"></span>
</div>
<span>€</span>
</label>
<label class="flex gap-1 justify-center items-center py-2 px-3 border border-neutral-300 cursor-text focus-within:ring-4 focus-within:ring-blue-200 rounded-md">
<div x-data="{value:to}" class="relative h-full">
<input class="text-center border-0 p-0 w-full absolute top-0 left-0 bg-transparent focus:border-none focus:ring-0" x-model="value" type="text" name="from" x-effect="value=Math.max(from, to)" @keyup.enter="triggerChange(value,'to')" @blur="triggerChange(value,'to')">
<span class="invisible block w-auto overflow-auto text-nowrap min-w-6 h-full" x-text="value"></span>
</div>
<span>€</span>
</label>
</div>
</div>
<script>
function rangeSlider() {
return {
// slider start value
min: 0,
// slider end value
max: 100,
// range start
from: 10,
// range end
to: 80,
// flag if mouse is clicked or screen is touched
dragFrom: false,
dragTo: false,
// call on x-init
init: function(min, max, from, to) {
// register mouse/touche move events to window
window.addEventListener("mousemove", (e) => {
this.drag(e)
});
window.addEventListener("touchmove", (e) => {
this.drag(e)
});
window.addEventListener("mouseup", this.dragEnd.bind(this));
window.addEventListener("touchend", this.dragEnd.bind(this));
// set values
this.min = min || this.min;
this.max = max || this.max;
this.from = from || this.from;
this.to = to || this.to;
},
triggerChange(value, type = 'from') {
value = parseInt(value);
if (isNaN(value)) {
const {
from,
to
} = this;
this.from = this.to = 0;
this.from = from;
this.to = to;
return;
}
if (this.from > this.to && value < this.max && value > this.min) {
this[type === 'to' ? 'from' : 'to'] = this[type];
this[type] = value;
return;
}
if (type === 'to') {
this.to = 0;
this.to = Math.min(this.max, value < this.from ? this.from : value);
if (value < this.from) {
this.from = value < this.min ? this.min : value;
}
} else {
this.from = 0;
this.from = Math.max(this.min, value > this.to ? this.to : value);
if (value > this.to) {
this.to = value > this.max ? this.max : value;
}
}
return value;
},
getFromPos: function() {
// return relative slider position for 'from' value
return ((this.from - this.min) / (this.max - this.min) * 100) + '%'
},
getToPos: function() {
// return relative slider position for 'to' value
return ((this.to - this.min) / (this.max - this.min) * 100) + '%'
},
getWidth: function() {
// return relative width between 'from' and 'to' value
return ((Math.max(this.to, this.from) - Math.min(this.to, this.from)) / (this.max - this.min) * 100) + '%'
},
getMinPos: function() {
// return the smallest of 'from' or 'to' value
if (this.from < this.to) {
return this.getFromPos();
}
return this.getToPos();
},
drag: function($event) {
if (!this.dragFrom && !this.dragTo) {
return;
}
// get touch/mouse x-coordinate
let x;
const rect = this.$refs.slider.getBoundingClientRect();
if ($event.type === 'touchmove') {
x = $event.changedTouches[0].clientX - rect.left + this.$refs.slider.offsetLeft;
} else {
x = $event.clientX - rect.left + this.$refs.slider.offsetLeft; //x position within the element.
}
// calculate the value relative to the mouse/touch x-position on the document
let pos = Math.round((this.max - this.min) * (x - this.$refs.slider.offsetLeft) / this.$refs.slider.clientWidth) + this.min;
//console.log($event);
// stay in range
pos = pos > this.max ? this.max : pos;
pos = pos < this.min ? this.min : pos;
if (this.dragFrom) {
this.from = pos;
}
if (this.dragTo) {
this.to = pos;
}
},
dragEnd: function() {
this.dragFrom = false;
this.dragTo = false;
}
}
}
</script>
</div>
</div>
</div>
{% set accordionContent %}
<div class="pb-4 md:pb-3">
{% render "@multiple-range-slider" with {suffix:'€'} %}
</div>
{% endset %}
{% render "@accordion--filter" with {title:title,content:accordionContent} %}
/* No context defined. */
No notes defined.