chore(filters): filter card responsiveness; slider appearance and functionality

This commit is contained in:
2026-03-13 19:14:18 +01:00
parent 1bf7596b80
commit 45947cd491
2 changed files with 93 additions and 88 deletions
+83 -69
View File
@@ -1,6 +1,7 @@
<template> <template>
<div class="filter-slider"> <div class="filter-slider-container">
<input <input
class="slider"
v-for="slider in sliderGroupsOptions[sliderGroup]" v-for="slider in sliderGroupsOptions[sliderGroup]"
type="range" type="range"
:name="slider.id" :name="slider.id"
@@ -10,6 +11,8 @@
:step="slider.step" :step="slider.step"
v-model="filters[slider.id]" v-model="filters[slider.id]"
/> />
<div class="slider-track" @click="moveCloserSliderToMousePos"></div>
</div> </div>
</template> </template>
@@ -25,90 +28,113 @@ const props = defineProps({
required: true required: true
} }
}); });
// Change slider value that's the closest one to the mouse position on the slider track click
function moveCloserSliderToMousePos(e: MouseEvent) {
const { clientX, target } = e;
const { minRange, maxRange, step } = sliderGroupsOptions[props.sliderGroup][0];
const boundingRect = (target as HTMLElement).getBoundingClientRect();
const mouseX = clientX - boundingRect.left;
const leftSliderValue = filters[sliderGroupsOptions[props.sliderGroup][0].id];
const rightSliderValue = filters[sliderGroupsOptions[props.sliderGroup][1].id];
let mouseValue = Math.round((maxRange - minRange) * (mouseX / boundingRect.width));
// Adjust mouse value to the closest step point (divide by 10, get rounded number, then multiply by step)
mouseValue = Math.round(mouseValue / step) * step;
let sliderIndex =
Math.abs(leftSliderValue - mouseValue) < Math.abs(rightSliderValue - mouseValue) ? 0 : 1;
filters[sliderGroupsOptions[props.sliderGroup][sliderIndex].id] = mouseValue;
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@use '../../styles/responsive'; @use '../../styles/responsive';
.filter-slider { .filter-slider-container {
position: relative; position: relative;
padding: 0.5em; padding: 0.5em;
height: 1.25em;
} }
.filter-slider > input { .slider-track {
position: absolute; position: absolute;
top: 0;
left: 0;
width: 100%; width: 100%;
height: 100%;
border-radius: 1em;
z-index: 10;
cursor: pointer;
background-color: #444;
transition: background-color 0.2s;
&:hover {
background-color: #4d4d4d;
}
}
.slider {
width: 100%;
height: 1.25em;
background: none;
outline: none;
border-radius: 1em;
padding: 0;
position: absolute;
left: 0;
top: 50%; top: 50%;
transform: translateY(-50%); transform: translateY(-50%);
z-index: 100;
pointer-events: none;
cursor: pointer;
-webkit-appearance: none; -webkit-appearance: none;
appearance: none; appearance: none;
background: none;
border: none;
outline: none;
pointer-events: none;
&:focus-visible ~ * { &:hover ~ .slider-track {
color: gold; background-color: #4d4d4d;
}
&:focus-visible {
outline: 1px solid white;
} }
&::-webkit-slider-thumb { &::-webkit-slider-thumb {
-webkit-appearance: none; -webkit-appearance: none;
appearance: none; appearance: none;
pointer-events: all;
position: relative;
z-index: 100; z-index: 100;
height: 20px; width: 1.25em;
width: 20px; height: 1.25em;
margin-top: -7px; border-radius: 1em;
background: var(--clr-primary);
border-radius: 50%; pointer-events: all;
background-color: var(--clr-primary);
@include responsive.smallScreen {
width: 15px;
height: 15px;
margin-top: -5px;
}
} }
&::-moz-range-thumb { &::-moz-range-thumb {
pointer-events: all; width: 1.25em;
height: 1.25em;
position: relative;
z-index: 10;
height: 1em;
width: 1em;
border-radius: 50%;
background-color: #333;
border: 3px solid var(--clr-primary);
cursor: pointer;
@include responsive.smallScreen {
width: 1em;
height: 1em;
}
}
&::-webkit-slider-runnable-track {
position: relative;
z-index: 1;
width: 100%;
height: 5px;
cursor: pointer;
border-radius: 1em; border-radius: 1em;
background: var(--clr-primary);
pointer-events: all;
} }
&:first-child::-webkit-slider-runnable-track { // &:first-child::-webkit-slider-runnable-track {
background: var(--clr-primary); // }
}
&::-moz-range-track { &::-moz-range-track {
position: relative; position: relative;
@@ -121,20 +147,8 @@ const props = defineProps({
border-radius: 1em; border-radius: 1em;
} }
&:first-child::-moz-range-track { // &:first-child::-moz-range-track {
background: var(--clr-primary); // background: var(--clr-primary);
} // }
&::-ms-track {
width: 100%;
height: 5px;
cursor: pointer;
background: none;
border-radius: 1em;
}
&:first-child::-ms-track {
background: white;
}
} }
</style> </style>
@@ -137,7 +137,7 @@
</section> </section>
<section class="card_sliders"> <section class="card_sliders">
<div class="slider-box" v-for="(sliderGroup, i) in sliderGroups" :key="i"> <div class="option-slider" v-for="(sliderGroup, i) in sliderGroups" :key="i">
<FilterSlider :sliderGroup="sliderGroup" /> <FilterSlider :sliderGroup="sliderGroup" />
<span class="slider-value"> <span class="slider-value">
@@ -593,38 +593,29 @@ h3.hours-section-header {
margin-top: 1em; margin-top: 1em;
} }
.slider-box { .option-slider {
display: grid; display: grid;
align-items: center; align-items: center;
grid-template-columns: 250px 100px 1fr; grid-template-columns: 250px 100px 1fr;
gap: 0.25em; gap: 0.25em;
margin-bottom: 1em; margin-bottom: 1em;
&-value {
color: var(--clr-primary);
padding: 0.1em 0.2em;
text-align: center;
}
} }
.slider-value { .slider-value {
color: var(--clr-primary);
padding: 0.1em 0.2em;
text-align: center; text-align: center;
font-weight: bold;
} }
@include responsive.smallScreen { @include responsive.smallScreen {
.slider-box { .option-slider {
display: flex; grid-template-columns: 1fr;
flex-wrap: wrap; }
justify-content: center;
&-input { .slider-content {
width: 90%; text-align: center;
}
&-content {
text-align: center;
}
} }
.card_controls > button > p { .card_controls > button > p {