# ZeenStreamProgramTable

Компонет слайдер

# Примеры:

Default

Расписание

10:00-11:00
Название трансляции, которое написано примерно на 3 строки или чуть меньше
10:00-11:00
live
Название трансляции, которое написано примерно на 3 строки или чуть меньше
10:00-11:00
Название трансляции, которое написано примерно на 3 строки или чуть меньше
Имя спикера

:speeches="speech"
:arrows="false"
:scrollToOnline="false"

Другой текст

10:00-11:00
Название трансляции, которое написано примерно на 3 строки или чуть меньше
10:00-11:00
live
Название трансляции, которое написано примерно на 3 строки или чуть меньше
10:00-11:00
Название трансляции, которое написано примерно на 3 строки или чуть меньше
Имя спикера

# props

Название Тип Обязательный По умолчанию Описание
speech Array - true - Массив из компонетов карточек (как заполнять карточки смотрите в компоненте ZeenStreamProgramItem)
arrows Boolean - true Показывать стрелки
scrollToOnline Boolean - true Автоскролл до онлайна
settingsSwiper Object - см.ниже Объект конфигурации swiper

const defaultSettingSwiper = { breakpoints: { 1336: { slidesPerView: 2.2, spaceBetween: 20, }, 1024: { slidesPerView: 2, spaceBetween: 20, }, 768: { slidesPerView: 1.5, spaceBetween: 20, }, 320: { slidesPerView: 1.08, spaceBetween: 10, }, }, }

# Source Code - исходный код компонента

<template lang="pug">
  .stream-table
    ZeenContainer
      .stream-table__header
        slot(name="title")
        .stream-table__arrows(v-if="arrows")
          ZeenActionIcon(size="big" ref="btnPrev")
            slot(name="arrowPrev")
              svg.stream-table__arrow(
                width="27"
                height="24"
                viewBox="0 0 27 24"
                xmlns="http://www.w3.org/2000/svg"
              )
                path(
                  fill-rule="evenodd"
                  clip-rule="evenodd"
                  d="M27 12C27 11.4477 26.5523 11 26 11H1C0.447716 11 0 11.4477 \
                  0 12C0 12.5523 0.447716 13 1 13H26C26.5523 13 27 12.5523 27 12Z"
                )
                path(
                  fill-rule="evenodd"
                  clip-rule="evenodd"
                  d="M13.2628 0.324281C12.8897 0.7314 12.9172 1.36397 13.3243 \
                  1.73716L24.5201 12L13.3243 22.2629C12.9172 22.636 12.8897 23.2686 \
                  13.2628 23.6757C13.636 24.0828 14.2686 24.1104 14.6757 23.7372L26.6757 \
                  12.7372C26.8824 12.5477 27 12.2803 27 12C27 11.7197 26.8824 11.4523 \
                  26.6757 11.2629L14.6757 0.262852C14.2686 -0.110341 13.636 -0.0828378 \
                  13.2628 0.324281Z"
                )
          ZeenActionIcon(size="big" ref="btnNext")
            slot(name="arrowNext")
              svg(width="27" height="24" viewBox="0 0 27 24" xmlns="http://www.w3.org/2000/svg")
                path(
                  fill-rule="evenodd"
                  clip-rule="evenodd"
                  d="M27 12C27 11.4477 26.5523 11 26 11H1C0.447716 11 0 11.4477 0 12C0 \
                  12.5523 0.447716 13 1 13H26C26.5523 13 27 12.5523 27 12Z"
                )
                path(
                  fill-rule="evenodd"
                  clip-rule="evenodd"
                  d="M13.2628 0.324281C12.8897 0.7314 12.9172 1.36397 13.3243 1.73716L24.5201 \
                  12L13.3243 22.2629C12.9172 22.636 12.8897 23.2686 13.2628 23.6757C13.636 \
                  24.0828 14.2686 24.1104 14.6757 23.7372L26.6757 12.7372C26.8824 12.5477 27 \
                  12.2803 27 12C27 11.7197 26.8824 11.4523 26.6757 11.2629L14.6757 0.262852C14.2686 \
                  -0.110341 13.636 -0.0828378 13.2628 0.324281Z"
                )
      .stream-table__wrapper.swiper-container(ref="slider")
        .swiper-wrapper
          .swiper-slide(
            v-for="(speech, i) in speeches"
            :key="speech.id"
          )
            ZeenStreamProgramItem(
              :key="i"
              :speech="speech"
              :modalName="`${modalPrefix}speech-speakers-${speech.id}`"
              @open-modal="openModal"
              v-on="speechEvents"
            )
              template(v-for="(slot, slotName) in speechSlots" v-slot:[slotName]="params")
                slot(:name="`${speechPrefix}${slotName}`" v-bind="params" )
    template(v-for="(speech, i) in speeches")
      ZeenModal(:name="`${modalPrefix}speech-speakers-${speech.id}`" :key="i")
        p.stream-item__modal-title {{ speakerTitle }}
        ZeenSpeakerItem.stream-item__speaker.stream-item__speaker_modal(
          v-for="(speaker, idx) in speech.speakers"
          :speaker="speaker"
          :key="idx"
        )
</template>

<script>
import Swiper from 'swiper/bundle'
import ZeenContainer from '../ZeenContainer/ZeenContainer'
import ZeenStreamProgramItem from '../ZeenStreamProgramItem/ZeenStreamProgramItem'
import ZeenActionIcon from '../ZeenActionIcon/ZeenActionIcon'
import ZeenModal from '../ZeenModal/ZeenModal'
import ZeenSpeakerItem from '../ZeenSpeakerItem/ZeenSpeakerItem'
import {createSlotsFor} from '../../helpers/createBlockData'

const defaultSettingSwiper = {
  breakpoints: {
    1336: {
      slidesPerView: 2.2,
      spaceBetween: 20,
    },
    1024: {
      slidesPerView: 2,
      spaceBetween: 20,
    },
    768: {
      slidesPerView: 1.5,
      spaceBetween: 20,
    },
    320: {
      slidesPerView: 1.08,
      spaceBetween: 10,
    },
  },
}

export default {
  name: 'ZeenStreamProgramTable',
  components: {
    ZeenSpeakerItem,
    ZeenModal,
    ZeenContainer,
    ZeenStreamProgramItem,
    ZeenActionIcon,
  },
  props: {
    speeches: {
      type: Array,
      require: true,
    },
    settingsSwiper: {
      type: Object,
      require: false,
      default: () => JSON.parse(JSON.stringify(defaultSettingSwiper)),
    },
    arrows: {
      type: Boolean,
      default: true,
    },
    scrollToOnline: {
      type: Boolean,
      default: true,
    },
    modalPrefix: String,
    speakerTitle: {
      type: String,
      default: 'Спикеры трансляции',
    },
  },
  mounted() {
    this.initSlider()
  },
  destroyed() {
    this.slider?.destroy(true, true)
  },
  methods: {
    initSlider() {
      const config = Object.assign({}, defaultSettingSwiper, this.settingsSwiper)
      if (this.arrows) {
        config.navigation = {
          prevEl: this.$refs.btnPrev.$el,
          nextEl: this.$refs.btnNext.$el,
        }
      }
      this.slider = new Swiper(this.$refs.slider, config)
      this.updateSlider()

      if (this.scrollToOnline) {
        this.autoScroll()
      }
    },
    autoScroll() {
      let online = 0
      this.speeches.some((item, index) => {
        if (item.status === 'online') {
          online = index
          return true
        }
      })
      this.slider.slideTo(online, 250, false)
    },
    async updateSlider() {
      if (!this.slider) {
        return
      }
      await this.$nextTick()
      this.slider.update()
    },
    openModal(modalName) {
      this.$vfm.show(modalName)
    },
  },
  computed: {
    speechPrefix() {
      return 'speech_'
    },
    speechEvents() {
      const prefix = this.speechPrefix
      const events = this.$listeners
      const entryEventNames = Object.keys(events)
        .filter((key) => key.substring(0, prefix.length) === prefix)
        .map((key) => key.substring(prefix.length))
      return entryEventNames.reduce((acc, entryKey) => {
        acc[entryKey] = events[`${prefix}${entryKey}`]
        return acc
      }, {})
    },
    speechSlots() {
      return createSlotsFor(this, this.speechPrefix)
    },
  },
  watch: {
    speeches() {
      setTimeout(() => {
        this.updateSlider()
      }, 1000)
    },
  },
}
</script>

<style>
:root {
  /* Размеры */
  --stream-table-arrow-width: 80px;
  --stream-table-dot-width: 10px;
  --stream-table-swiper-margin-top: 30px;
  --stream-program-item-title-mobile-font-size: var(--main-larger-size);
  --stream-program-item-title-mobile-font-weight: 600;
  --stream-program-modal-speaker-margin-top: 30px;

  /* Цвета */
  --stream-table-dot-background: var(--gray-2);
  --stream-table-dot-background-active: var(--main-color);
}
</style>

<style lang="scss" scoped>
@import './src/styles/mixins.scss';

.stream-table {
  width: 100%;

  &__header {
    width: 100%;
    display: flex;
    justify-content: space-between;
    align-items: center;
  }

  &__arrows {
    width: var(--stream-table-arrow-width);
    display: flex;
    justify-content: space-between;
  }

  &__arrow {
    transform: rotateY(180deg);
  }

  &__wrapper {
    margin-top: var(--stream-table-swiper-margin-top);
  }

  ::v-deep {
    .swiper-slide {
      height: auto;
      display: flex;
      flex-direction: column;
      box-sizing: border-box;
    }
  }
}

.stream-item {
  &__modal-title {
    font-weight: var(--stream-program-item-title-mobile-font-weight);
    font-size: var(--stream-program-item-title-mobile-font-size);
    line-height: 1.3;
    margin: 0 0;
  }

  &__speaker {
    margin-top: var(--stream-program-modal-speaker-margin-top);
    width: 100%;

    &_modal {
      max-width: none;
    }
  }
}
</style>