Added unidentified actors and actor count filters.
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
<script setup>
|
||||
import {
|
||||
computed,
|
||||
ref,
|
||||
} from 'vue';
|
||||
|
||||
import Range from '#/components/form/range.vue';
|
||||
|
||||
const props = defineProps({
|
||||
filters: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
counts: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update']);
|
||||
|
||||
// beyond this the slider loses too much fidelity for the common small counts, the last step means 'or more'
|
||||
const sliderCap = 10;
|
||||
|
||||
const rows = [
|
||||
{ key: 'group', label: 'Actors', icon: 'users' },
|
||||
{ key: 'females', label: 'Females', icon: 'female' },
|
||||
{ key: 'males', label: 'Males', icon: 'male' },
|
||||
{ key: 'trans', label: 'Trans', icon: 'transsexual' },
|
||||
];
|
||||
|
||||
// values while dragging, before the change is committed and the scenes reload
|
||||
const dragging = ref({});
|
||||
|
||||
const sliders = computed(() => rows.map((row) => {
|
||||
const filter = props.filters[row.key];
|
||||
const buckets = props.counts?.[row.key] || [];
|
||||
const countMax = buckets.at(-1)?.value ?? sliderCap; // buckets are sorted by value
|
||||
// at least 1 to keep the slider usable, and never below the active filter so its handles stay in view
|
||||
const max = Math.max(1, Math.min(countMax, sliderCap), filter?.min ?? 0, filter?.max ?? 0);
|
||||
const value = [filter?.min ?? 0, filter?.max ?? max];
|
||||
|
||||
return {
|
||||
...row,
|
||||
max,
|
||||
isCapped: countMax > max,
|
||||
value,
|
||||
display: dragging.value[row.key] || value,
|
||||
mountKey: `${row.key}-${max}-${value.join('-')}`, // remount when the range or filter changes, the slider only reads its value on mount
|
||||
};
|
||||
}));
|
||||
|
||||
function getEndLabel(slider, value) {
|
||||
return value === slider.max && slider.isCapped ? `${value}+` : value;
|
||||
}
|
||||
|
||||
function updateRange(slider, [min, max], reload) {
|
||||
if (!reload) {
|
||||
dragging.value[slider.key] = [min, max];
|
||||
return;
|
||||
}
|
||||
|
||||
delete dragging.value[slider.key];
|
||||
|
||||
// the top of the slider means 'or more', the full range means no filter
|
||||
const range = {
|
||||
min,
|
||||
max: max === slider.max ? null : max,
|
||||
};
|
||||
|
||||
emit('update', slider.key, min === 0 && range.max === null ? null : range, true);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="filter groups-container">
|
||||
<div
|
||||
v-for="slider in sliders"
|
||||
:key="slider.key"
|
||||
class="filter-row"
|
||||
:title="slider.label"
|
||||
>
|
||||
<Icon
|
||||
:icon="slider.icon"
|
||||
:class="`gender-${slider.key}`"
|
||||
/>
|
||||
|
||||
<Range
|
||||
:key="slider.mountKey"
|
||||
:min="0"
|
||||
:max="slider.max"
|
||||
:value="slider.value"
|
||||
:allow-enable="false"
|
||||
@input="(range) => updateRange(slider, range, false)"
|
||||
@change="(range) => updateRange(slider, range, true)"
|
||||
>
|
||||
<template #start><span class="range-label">{{ slider.display[0] }}</span></template>
|
||||
<template #end><span class="range-label">{{ getEndLabel(slider, slider.display[1]) }}</span></template>
|
||||
</Range>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.groups-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: .5rem 0;
|
||||
}
|
||||
|
||||
.filter-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0 .25rem;
|
||||
|
||||
.range-container {
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.range-label {
|
||||
display: inline-block;
|
||||
min-width: 1.5rem;
|
||||
color: var(--glass-strong-10);
|
||||
font-size: .9rem;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.range-container {
|
||||
padding: .25rem 0;
|
||||
}
|
||||
|
||||
.icon {
|
||||
fill: var(--glass);
|
||||
}
|
||||
|
||||
.gender-females {
|
||||
fill: var(--female);
|
||||
}
|
||||
|
||||
.gender-males {
|
||||
fill: var(--male);
|
||||
}
|
||||
|
||||
.gender-trans {
|
||||
fill: var(--trans);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user