designtopack/src/components/Selector.vue

222 lines
5.2 KiB
Vue

<template>
<div
id="selector-dropdown"
class="flex flex-col"
:style="'--image: url(\'' + getFrontViewUrl(currentValue) + '\')'"
>
<label for="selector-select" class="text-sm">{{ label }}</label>
<Select
id="selector-select"
v-model="currentValue"
:options="items"
optionLabel="title"
class="font-serif"
data-icon="chevron-single-down"
checkmark
>
<template #value="slotProps">
<p v-if="currentValue && !Array.isArray(currentValue)">
{{ currentValue.title }}
</p>
<p v-else>Select...</p>
</template>
<template #option="slotProps">
<img
alt=""
:src="getFrontViewUrl(slotProps.option)"
width="28"
height="28"
/>
<p>{{ slotProps.option.title }}</p>
</template>
</Select>
</div>
</template>
<script setup>
import { ref, watch } from 'vue';
import { storeToRefs } from 'pinia';
import { useDialogStore } from '../stores/dialog';
const { items, label, isCompareModeEnabled } = defineProps({
label: String,
items: Array,
isCompareModeEnabled: {
type: Boolean,
default: false,
},
});
const emit = defineEmits(['update:selectedItems']);
const currentValue = ref(isCompareModeEnabled ? [] : null);
const { activeTracks } = storeToRefs(useDialogStore());
watch(currentValue, (newValue) => {
if (
newValue !== null &&
(Array.isArray(newValue) ? newValue.length > 0 : true)
) {
changeCurrent(newValue);
}
});
watch(activeTracks, (newValue) => {
if (newValue[newValue.length - 1] !== currentValue.value) {
currentValue.value = isCompareModeEnabled ? [] : null;
}
});
function changeCurrent(item) {
emit('update:selectedItems', item);
}
function getFrontViewUrl(item) {
if (!item) return '';
if (Array.isArray(item)) {
return item.length > 0 ? getFrontViewUrl(item[0]) : '';
}
if (item.files.length > 1) {
return item.files[7]?.url || item.files[0].url;
} else {
return item.files[0].url;
}
}
</script>
<style>
#selector-dropdown {
--selector-width: fit-content;
--row-gap: 0;
align-items: flex-start;
position: relative;
background: var(--color-background);
border-radius: var(--rounded-lg);
height: 3.75rem;
width: var(--selector-width, 20rem);
max-width: 20rem;
padding: var(--space-8) var(--space-48) var(--space-8) var(--space-64);
}
#selector-dropdown::before {
content: '';
position: absolute;
left: var(--space-8);
width: 2.75rem;
height: 2.75rem;
border-radius: var(--rounded-md);
background-color: var(--dialog-inner-background, #f7f7f7);
background-image: var(--image);
background-repeat: no-repeat;
background-size: cover;
background-position: center;
}
[role='combobox'],
#selector-select_list {
border: 1px solid var(--color-grey-200);
}
[role='combobox']:hover {
outline: 1px solid var(--color-grey-400);
border-color: var(--color-background);
}
[role='combobox'][aria-expanded='true'] {
outline: 2px solid var(--color-focus-ring);
outline-offset: -2px;
border-color: transparent;
}
#selector-select,
[role='combobox'] {
position: absolute;
inset: 0;
border-radius: inherit;
padding: 1.875rem var(--space-48) var(--space-8) var(--space-64);
cursor: pointer;
}
/* Icon */
#selector-select svg {
display: none; /* Hide default component svg */
}
#selector-select[data-icon]::before {
--icon-color: var(--color-grey-700);
position: absolute;
right: var(--space-8);
top: 0.625rem;
width: 2.5rem;
height: 2.5rem;
padding: 0.625rem;
}
#selector-dropdown label {
color: var(--color-grey-700);
letter-spacing: var(--tracking-wider);
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
height: 1lh;
padding-right: 1em;
}
/* Options */
#selector-select_list {
margin-top: var(--space-4);
border-radius: var(--rounded-md);
background: var(--color-background);
box-shadow: var(--shadow);
padding: var(--space-8);
}
#selector-select_list > * {
font-family: var(--font-serif);
padding: var(--space-8) var(--space-8) var(--space-8) var(--space-48);
border-radius: var(--rounded-sm);
position: relative;
display: flex;
align-items: center;
height: 2.75rem;
cursor: pointer;
}
#selector-select_list > * + * {
margin-top: var(--space-4);
}
#selector-select_list > *::before {
content: '';
position: absolute;
left: var(--space-8);
width: 1.75rem;
height: 1.75rem;
border-radius: var(--rounded-sm);
background-image: var(--image);
background-color: var(--dialog-inner-background, #f7f7f7);
background-repeat: no-repeat;
background-size: cover;
background-position: center;
}
#selector-select_list > *:hover {
background-color: var(--color-grey-50);
}
#selector-select_list > *:focus,
#selector-select_list > *:focus-visible,
#selector-select_list > [data-p-focused='true'] {
outline: 2px solid var(--color-focus-ring);
}
/* Check */
#selector-select_list > * > svg {
position: absolute;
left: 0.875rem;
width: 1rem;
height: 1rem;
color: var(--color-grey-700);
}
#selector-select_list img {
position: absolute;
left: 0.5rem;
width: 1.75rem;
height: 1.75rem;
mix-blend-mode: multiply;
}
#selector-select_list [aria-selected='true'] img {
display: none;
}
</style>