<template> <ComboBox :model-value="selectedShow" :label="t('showSelector.selectShow')" :no-data-label="hasShows ? t('showSelector.noDataMatch') : t('showSelector.noData')" :keyboard-shortcut="!isMac ? keys.alt_k : undefined" :keyboard-shortcut-label="t('showSelector.keyboardShortcut')" :choices="filteredShows" data-testid="show-selector" @update:model-value="showStore.selectedShowId = $event.id" @search="showSearchQuery = $event" @close="filterActive = null" > <template #default="{ choice, index, activeIndex, ...attrs }"> <li v-bind="attrs"> <p class="tw-m-0 tw-font-bold tw-flex tw-items-baseline tw-justify-between"> <SafeHTML :html="(choice as Show).name" sanitize-preset="strip" /> <span class="tw-text-xs tw-opacity-75 tw-flex-none tw-font-normal"> ID: {{ (choice as Show).id }} </span> </p> <span v-if="!(choice as Show).isActive" class="tw-text-sm tw-rounded-full tw-bg-black/10 tw-text-black/75 tw-px-2 tw-inline-block tw-float-right tw-m-0 tw-ml-1 tw-mb-1" > {{ t('showSelector.showState.inactive') }} </span> <SafeHTML v-show="activeIndex === index" as="p" class="tw-my-1 tw-text-sm tw-opacity-90" :html="(choice as Show).shortDescription" /> <span class="tw-clear-both" /> </li> </template> <template #selected="{ isOpen }"> <span v-if="!isOpen && selectedShow" class="tw-absolute tw-pointer-events-none tw-top-8 tw-left-3 tw-truncate" style="max-width: calc(100% - 5.5rem)" > <SafeHTML :html="selectedShow.name" sanitize-preset="strip" /> </span> </template> <template #filter> <div v-if="hasShows"> <p class="mb-2 tw-text-sm tw-font-bold">{{ t('showSelector.showState.label') }}</p> <div class="tw-flex tw-text-sm tw-border tw-border-solid tw-border-gray-200 tw-w-min tw-rounded" > <SwitchButton :model-value="filterActive === true" class="tw-whitespace-nowrap" :label="t('showSelector.showState.active')" @update:model-value="toggleFilterActive(true)" /> <SwitchButton :model-value="filterActive === false" class="tw-whitespace-nowrap" :label="t('showSelector.showState.inactive')" @update:model-value="toggleFilterActive(false)" /> </div> </div> <div class="tw-block" :class="{ 'tw-mt-auto': hasShows }"> <AddShowButton test-id="show-selector:add-show" /> </div> </template> </ComboBox> </template> <script lang="ts" setup> import { sort } from 'fast-sort' import { computed, ref } from 'vue' import { useMagicKeys } from '@vueuse/core' import { useI18n } from '@/i18n' import { sanitizeHTML } from '@/util' import { useAuthStore, useShowStore } from '@/stores' import SwitchButton from '@/components/SwitchButton.vue' import ComboBox from '@/components/ComboBox.vue' import AddShowButton from '@/components/shows/AddShowButton.vue' import SafeHTML from '@/components/generic/SafeHTML' import { Show } from '@/types' defineOptions({ compatConfig: { MODE: 3 } }) const keys = useMagicKeys() const { t } = useI18n() const showStore = useShowStore() const authStore = useAuthStore() const selectedShow = computed<Show | null>(() => showStore.selectedShow) const showSearchQuery = ref('') const filterActive = ref<null | boolean>(null) const isMac = navigator.platform.toLowerCase().includes('mac') const hasShows = computed(() => showStore.items.length > 0) const sortedShows = computed(() => { return sort(showStore.items).by([ { desc: (show) => show.isActive }, { asc: (show) => sanitizeHTML(show.name).toLowerCase() }, ]) }) const filteredShows = computed(() => { return ( sortedShows.value .filter((show) => (filterActive.value !== null ? show.isActive === filterActive.value : true)) // FIXME: Re-implementation of the ?isWritable=1 filter on the show API endpoint. // If we’re keeping the show selector it should be refactored to use the API. .filter( (show) => authStore.steeringUser?.isPrivileged || (authStore.steeringUser && show.ownerIds.includes(authStore.steeringUser.id)), ) .filter( (show) => sanitizeHTML(show.name).toLocaleLowerCase().includes(showSearchQuery.value) || show.id.toString() === showSearchQuery.value, ) ) }) function toggleFilterActive(toggleState: boolean) { if (filterActive.value === toggleState) { filterActive.value = null return } filterActive.value = toggleState } </script>