Skip to content
Snippets Groups Projects
ShowSelector.vue 4.19 KiB
Newer Older
<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 #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">
          <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 { 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 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))
    .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>