# ZeenSchedule
Компонент ZeenSchedule
# Примеры:
Размеры:
ZeenSchedule
zeen-schedule-header-margin-bottom
zeen-schedule-container-max-width
zeen-schedule-arrows-width
zeen-schedule-col-padding-bottom
zeen-schedule-time-text-size
По умолчанию наследуется от main-large-size
zeen-schedule-time-line-height
zeen-schedule-time-font-weight
zeen-schedule-time-width
zeen-schedule-hall-border-radius
zeen-schedule-col-line-size
zeen-schedule-row-height
zeen-schedule-hall-text-size
По умолчанию наследуется от main-small-text
zeen-schedule-hall-line-height
zeen-schedule-hall-font-weight
zeen-schedule-hall-padding-vertical
zeen-schedule-hall-padding-horizontal
zeen-schedule-hall-arrow-size
zeen-schedule-hall-arrow-margin-left
zeen-schedule-online-img-size
zeen-schedule-card-height
Цвета:
zeen-schedule-background
По умолчанию наследуется от main-light
zeen-schedule-col-border
По умолчанию наследуется от gray-1
zeen-schedule-time-color
По умолчанию наследуется от main-color
zeen-schedule-time-color-done
По умолчанию наследуется от gray-2
zeen-schedule-col-line
По умолчанию наследуется от gray-1
zeen-schedule-online-line
По умолчанию наследуется от main-danger-color
zeen-schedule-online-img
По умолчанию наследуется от main-light
zeen-schedule-hall
По умолчанию наследуется от gray-1
zeen-schedule-hall-active
По умолчанию наследуется от main-transparent
zeen-schedule-hall-hover
По умолчанию наследуется от main-transparent
zeen-schedule-hall-text
По умолчанию наследуется от input-main-value-color
zeen-schedule-hall-text-active
По умолчанию наследуется от main-color
zeen-schedule-hall-arrow-color
Программа дня
# props
Название | Тип | Обязательный | По умолчанию | Описание |
---|---|---|---|---|
streams | Array | + | - | Массив стримов со спичами и спикерами |
activeStreamId | String | - | '' | id активной страницы зала |
speechModalProps | Object | - | - | Пропсы для модалки speechModal |
speechCardProps | Object | - | - | Пропсы для модалки ZeenScheduleCard |
marginBeforeOnline | Number | - | 50 | Отступ от края окна после скролла слайдером до онлайн спича |
timeRowStep | Number | - | 5 | Максимальное кол-во делений у карточки спича |
scrollLimit | Number | - | 2 | Ограничение скролла по стрелкам относительно видимой ширины окна , ширина/scrollLimit |
slideToggleBtnText | Object | - | open: 'Показать всё', close: 'Скрыть' | текст кнопки toggle |
offSlideToggle | Boolean | - | false | отключить toggle |
toggleProps | Object | - | 615 | пропсы ZeenSlideToggle |
hallOffset | Number | - | 24 | верхний отступ от границы колонки |
showOnlineLine | Boolean | - | false | отвечает за показ онлайн-линии |
visibleHallsCount | Number | - | 2 | количество видимых залов |
# emits
Название | Описание |
---|---|
cardClick | Срабатывает при клике по карточке передает объект с hall и speech |
cardButtonClick | Срабатывает при клике по кнопке карточки передает объект с hall и speech |
hallClick | Срабатывает при клике по залу передает объект с hall |
watchSpeech | Срабатывает при клике по "Смотреть" передает объект с hall и speech |
addToPersonalSchedule | Срабатывает при клике по "Добавить в расписание" передает объект с hall и speech |
removeFromPersonalSchedule | Срабатывает при клике по "Удалить из расписания" передает объект с hall и speech |
# slots
Название | Описание |
---|---|
title | title блока |
day-tab | таб для дней |
arrow-prev | иконка слайдера |
arrow-next | иконка слайдера |
hall-img | картинка для зала |
hall-arrow | стрелка для зала |
hall-tooltip | tooltip для зала |
popover | контент для tooltip |
online-line-icon | иконка онлайн линии |
slide-toggle-btn | кнопка для toggle |
# Source Code - исходный код компонента
<template lang="pug">
section.zeen-schedule
ZeenSpeechModal(
name='ZeenSchedule'
:speech='modalSpeech'
:hall='modalHall'
v-bind='speechModalProps'
v-on='modalEvents'
)
template(v-for='(slot, slotName) in modalSlots' v-slot:[slotName]='params')
slot(:name='`${modalPrefix}${slotName}`' v-bind='params')
ZeenContainer
.zeen-schedule__top
slot(name='title')
slot(name='top-btn')
slot(name='day-tab')
ZeenSlideToggle(:open='isOpen || offSlideToggle' v-bind='toggleProps' :closedHeight='closedHeight' )
.zeen-schedule__container
.zeen-schedule__arrows
ZeenActionIcon(
theme='button'
@click='prev'
:disabled='prevDisabled'
)
slot(name='arrow-prev')
svg(
width='100%'
height='100%'
viewBox='0 0 12 12'
xmlns='http://www.w3.org/2000/svg'
)
path(
fill-rule='evenodd' clip-rule='evenodd' d='M7.35667 1.10026C6.94389 \
0.73334 6.31182 0.77052 5.9449 1.1833L2.25259 5.33715C1.9158 5.71603 1.9158 \
6.28699 2.25259 6.66588L5.9449 10.8197C6.31182 11.2325 6.94389 11.2697 7.35667 \
10.9028C7.76945 10.5359 7.80664 9.90378 7.43972 9.491L4.33795 6.00151L7.43972 \
2.51203C7.80664 2.09925 7.76945 1.46718 7.35667 1.10026Z')
ZeenActionIcon(
theme='button'
@click='next'
:disabled='nextDisabled'
)
slot(name='arrow-next')
svg.zeen-schedule__arrow(
width='100%'
height='100%'
viewBox='0 0 12 12'
xmlns='http://www.w3.org/2000/svg'
)
path(
fill-rule='evenodd' clip-rule='evenodd' d='M7.35667 1.10026C6.94389 \
0.73334 6.31182 0.77052 5.9449 1.1833L2.25259 5.33715C1.9158 5.71603 1.9158 \
6.28699 2.25259 6.66588L5.9449 10.8197C6.31182 11.2325 6.94389 11.2697 7.35667 \
10.9028C7.76945 10.5359 7.80664 9.90378 7.43972 9.491L4.33795 6.00151L7.43972 \
2.51203C7.80664 2.09925 7.76945 1.46718 7.35667 1.10026Z')
.zeen-schedule__hall(
v-for='(hall, i) in streams'
:key='hall.id'
:class='activeHall[i]'
:style='hallLinkStyles[i]'
@click='hallClick(hall)'
)
slot(name='hall-img' :hall="hall")
| {{hall.name}}
slot(v-if="!hall.description" name='hall-arrow')
svg.zeen-schedule__hall-arrow(
width='100%'
height='100%'
viewBox='0 0 16 17'
xmlns='http://www.w3.org/2000/svg'
)
path(
fill-rule='evenodd'
clip-rule='evenodd'
d='M4.87471 14.3187C5.28749 14.6856 5.91956 14.6484 6.28648 14.2356L11.2096 8.69718C11.5463 \
8.31829 11.5463 7.74734 11.2096 7.36845L6.28648 1.82999C5.91956 1.41721 5.28749 1.38003 4.87471 \
1.74695C4.46193 2.11386 4.42475 2.74594 4.79166 3.15872L9.1242 8.03282L4.79166 12.9069C4.42475 \
13.3197 4.46193 13.9518 4.87471 14.3187Z')
slot(v-else name='hall-tooltip' :hall="hall")
VPopover(placement='top' trigger='hover' offset='5')
svg.zeen-schedule__hall-tooltip-icon(
width="100%"
height="100%"
viewBox="0 0 12 12"
xmlns="http://www.w3.org/2000/svg"
)
path(
fill-rule="evenodd"
clip-rule="evenodd"
d="M12 6C12 9.31371 9.31371 12 6 12C2.68629 12 0 9.31371 0 6C0 2.68629 2.68629 0 6 0C9.31371 \
0 12 2.68629 12 6ZM6.85686 3.42746C6.85686 3.90084 6.47311 4.2846 5.99972 4.2846C5.52633 \
4.2846 5.14258 3.90084 5.14258 3.42746C5.14258 2.95407 5.52633 2.57031 5.99972 2.57031C6.47311 \
2.57031 6.85686 2.95407 6.85686 3.42746ZM5.99972 5.14062C5.52633 5.14062 5.14258 5.52438 5.14258 \
5.99777V8.5692C5.14258 9.04258 5.52633 9.42634 5.99972 9.42634C6.47311 9.42634 6.85686 9.04258 6.85686 \
8.5692V5.99777C6.85686 5.52438 6.47311 5.14062 5.99972 5.14062Z")
.zeen-schedule__popover(slot="popover") {{ hall.description }}
.zeen-schedule__main(ref='schWidth')
.swiper-slider
.swiper-container(ref='slider')
.swiper-wrapper(:style='{transform: `translateX(${customTranslate}px)`}')
.swiper-slide
.zeen-schedule__wrapper
.zeen-schedule__online-line(
:style='onlineLeftSpacing'
v-if='onlineLeftSpacing'
)
span.zeen-schedule__online-circle
span.zeen-schedule__online-img
slot(name='online-line-icon')
svg(width='100%' height='100%' viewBox='0 0 16 14' xmlns='http://www.w3.org/2000/svg')
path(
d='M3.45301 1.16705C3.38625 1.09893 3.30672 1.04464 \
3.21896 1.00726C3.13121 0.969895 3.03695 0.950182 \
2.94158 0.949253C2.8462 0.948324 2.75158 0.966198 2.66312 \
1.00185C2.57465 1.03751 2.49408 1.09024 2.42601 1.15705C1.65596 \
1.92263 1.04512 2.83311 0.628737 3.83596C0.212354 4.83881 \
-0.00133197 5.91419 6.24671e-06 7.00005C-0.00124271 8.12757 \
0.22926 9.24331 0.677209 10.278C1.12516 11.3128 1.78099 12.2444 \
2.60401 13.015C2.74253 13.1431 2.9255 13.2121 3.11408 \
13.2074C3.30266 13.2028 3.48199 13.1248 3.61401 12.99C3.93001 \
12.674 3.89101 12.171 3.58701 11.88C2.9265 11.2506 2.4009 10.4934 \
2.04212 9.65447C1.68335 8.81556 1.49891 7.91246 1.50001 \
7.00005C1.50001 5.15405 2.24101 3.48005 3.44301 2.26205C3.73301 \
1.96705 3.76301 1.47705 3.45301 1.16705Z'
)
path(
d='M5.214 2.92927C5.0823 2.79376 4.90225 2.71598 4.71331 \
2.71298C4.52437 2.70998 4.34194 2.78201 4.206 2.91327C3.66483 \
3.44734 3.2353 4.08373 2.94242 4.78538C2.64953 5.48704 \
2.49914 6.23994 2.5 7.00027C2.5 8.69227 3.23 10.2133 4.393 \
11.2643C4.53025 11.3855 4.70889 11.4493 4.89191 11.4424C5.07492 \
11.4356 5.24826 11.3585 5.376 11.2273C5.704 10.8993 5.643 \
10.3833 5.335 10.0933C4.91281 9.6964 4.57651 9.21715 4.34689 \
8.68515C4.11727 8.15315 3.99921 7.57971 4 7.00027C4 5.85027 \
4.457 4.80627 5.2 4.04027C5.486 3.74627 5.533 3.24727 5.214 \
2.92927Z'
)
path(
d='M10.7858 2.92927C10.9175 2.79376 11.0976 2.71598 \
11.2865 2.71298C11.4755 2.70998 11.6579 2.78201 11.7938 \
2.91327C12.335 3.44734 12.7645 4.08373 13.0574 4.78538C13.3503 \
5.48704 13.5007 6.23994 13.4998 7.00027C13.4998 8.69227 12.7698 \
10.2133 11.6068 11.2643C11.4696 11.3855 11.2909 11.4493 11.1079 \
11.4424C10.9249 11.4356 10.7516 11.3585 10.6238 11.2273C10.2958 \
10.8993 10.3568 10.3833 10.6648 10.0933C11.087 9.6964 11.4233 \
9.21715 11.6529 8.68515C11.8826 8.15315 12.0006 7.57971 11.9998 \
7.00027C11.9998 5.85027 11.5428 4.80627 10.7998 4.04027C10.5138 \
3.74627 10.4668 3.24727 10.7858 2.92927Z'
)
path(
d='M12.5471 1.16705C12.6138 1.09893 12.6933 1.04464 \
12.7811 1.00726C12.8689 0.969895 12.9631 0.950182 \
13.0585 0.949253C13.1539 0.948324 13.2485 0.966198 \
13.3369 1.00185C13.4254 1.03751 13.506 1.09024 13.5741 \
1.15705C14.3441 1.92263 14.9549 2.83311 15.3713 3.83596C15.7877 \
4.83881 16.0014 5.91419 16.0001 7.00005C16.0013 8.12757 \
15.7708 9.24331 15.3229 10.278C14.8749 11.3128 14.2191 12.2444 \
13.3961 13.015C13.2575 13.1431 13.0746 13.2121 12.886 \
13.2074C12.6974 13.2028 12.5181 13.1248 12.3861 12.99C12.0701 \
12.674 12.1091 12.171 12.4141 11.88C13.0744 11.2505 13.5998 \
10.4933 13.9584 9.65435C14.317 8.81544 14.5013 7.91238 14.5001 \
7.00005C14.5001 5.15405 13.7591 3.48005 12.5571 2.26205C12.2671 \
1.96705 12.2371 1.47705 12.5471 1.16705Z'
)
path(
d='M8 5.5C7.60218 5.5 7.22064 5.65804 6.93934 5.93934C6.65804 \
6.22064 6.5 6.60218 6.5 7C6.5 7.39782 6.65804 7.77936 6.93934 \
8.06066C7.22064 8.34196 7.60218 8.5 8 8.5C8.39782 8.5 8.77936 \
8.34196 9.06066 8.06066C9.34196 7.77936 9.5 7.39782 9.5 7C9.5 \
6.60218 9.34196 6.22064 9.06066 5.93934C8.77936 5.65804 8.39782 \
5.5 8 5.5Z'
)
ul.zeen-schedule__col(ref='timeRow')
li.zeen-schedule__time(
v-for='(time, idx) in timeArray'
:key='idx'
ref='timeCol'
:class='timeRowDone[idx]'
) {{time}}
span.zeen-schedule__time-line(ref='colLine')
svg(width='100%' height='100%' viewBox='0 0 1 730' fill='none' xmlns='http://www.w3.org/2000/svg')
line(x1='0.5' y1='-2.12908e-08' x2='0.50005' y2='1113' stroke-dasharray='6 10')
.zeen-schedule__row(v-for='(hall, i) in streams' :key='i' ref='cardsRow')
ZeenScheduleCard.zeen-schedule__card(
v-for='(speech, i) in hall.speeches'
:key='i'
:speech='speech'
:width='colWidthAndTimeArray'
:coords='timeCoordsAndTime'
:hall='hall'
v-bind='speechCardProps'
@cardClick='cardClick'
@cardButtonClick='cardButtonClick'
ref='cards'
)
template(v-for='(slot, slotName) in speechSlots' v-slot:[slotName]='params')
slot(:name='`${speechPrefix}${slotName}`' v-bind='params')
.swiper-slide
span.zeen-schedule__span-slider
.zeen-schedule__hide-button(v-if='!offSlideToggle' @click='isOpen = !isOpen')
slot(name='slide-toggle-btn' :isOpen='isOpen')
ZeenButton {{ isOpen ? slideToggleBtnText.close : slideToggleBtnText.open }}
template(#rightIcon)
svg.zeen-schedule__hide-button-svg(
:class="{'zeen-schedule__hide-button-svg_open': isOpen}"
width="100%"
height="100%"
viewBox="0 0 16 16"
xmlns="http://www.w3.org/2000/svg"
)
path(
fill-rule="evenodd"
clip-rule="evenodd"
d="M14.2853 4.8735C14.6522 5.28628 14.615 5.91835 14.2022 6.28527L8.66377 \
11.2083C8.28489 11.5451 7.71393 11.5451 7.33505 11.2083L1.79658 6.28527C1.3838 \
5.91835 1.34662 5.28628 1.71354 4.8735C2.08046 4.46071 2.71253 4.42353 3.12531 \
4.79045L7.99941 9.12298L12.8735 4.79045C13.2863 4.42353 13.9184 4.46071 14.2853 4.8735Z"
)
</template>
<script>
import Swiper from 'swiper/bundle'
import {VPopover} from 'v-tooltip'
import ZeenScheduleCard from '../../components/ZeenScheduleCard/ZeenScheduleCard'
import ZeenContainer from '../../components/ZeenContainer/ZeenContainer'
import ZeenActionIcon from '../../components/ZeenActionIcon/ZeenActionIcon'
import ZeenSpeechModal from '../../components/ZeenSpeechModal/ZeenSpeechModal'
import ZeenSlideToggle from '../../components/ZeenSlideToggle/ZeenSlideToggle'
import ZeenButton from '../../components/ZeenButton/ZeenButton'
import {getMinutes, toStringTime, getCurrentTime} from '../../helpers/timeConverter'
import {createEventsFor, createSlotsFor} from '../../helpers/createBlockData'
export default {
name: 'ZeenSchedule',
components: {
ZeenScheduleCard,
ZeenContainer,
ZeenActionIcon,
ZeenSpeechModal,
ZeenSlideToggle,
ZeenButton,
VPopover,
},
props: {
streams: {
type: Array,
require: true,
},
activeStreamId: {
type: String,
default: '',
},
timeFormat: {
type: String,
default: 'HH:mm',
},
marginBeforeOnline: {
type: Number,
default: 50,
},
speechModalProps: Object,
speechCardProps: Object,
timeRowStep: {
type: Number,
default: 5,
},
scrollLimit: {
type: Number,
default: 2,
},
slideToggleBtnText: {
type: Object,
default: () => {
return {
open: 'Показать всё',
close: 'Скрыть',
}
},
},
offSlideToggle: {
type: Boolean,
default: true,
},
hallOffset: {
type: Number,
default: 24,
},
toggleProps: {
type: Object,
},
showOnlineLine: {
type: Boolean,
default: false,
},
visibleHallsCount: {
type: Number,
default: 2,
},
},
data() {
return {
slider: null,
customTranslate: 0,
diffBetweenSliderAndSch: 0,
nextDisabled: false,
prevDisabled: false,
modalSpeech: null,
modalHall: null,
timeCoordsAndTime: [],
colWidthAndTimeArray: null,
coordsToHall: [],
date: null,
intervalToCurrentTime: null,
isOpen: false,
}
},
async mounted() {
await this.$nextTick()
this.slider = new Swiper(this.$refs.slider, {
slidesPerView: 'auto',
grabCursor: true,
freeMode: true,
virtualTranslate: true,
on: {
setTranslate: () => {
this.customScroll()
},
touchEnd: () => {
this.prevOrNextDisabled()
},
resize: () => {
this.getDiffBetweenSliderAndSch()
this.coordsToHallFunc()
},
},
})
this.updateSlider()
this.date = getCurrentTime(this.timeFormat)
this.intervalToCurrentTime = setInterval(() => {
this.date = getCurrentTime(this.timeFormat)
}, 60 * 1000)
},
destroyed() {
this.slider?.destroy(true, true)
if (this.intervalToCurrentTime) clearInterval(this.intervalToCurrentTime)
},
methods: {
// Получаем координаты времени в временной шкале и само время
getTimeCoordsAndTime() {
const colCoord = this.$refs.timeRow?.getBoundingClientRect().left
const coords = this.$refs.colLine?.map((line) => line?.getBoundingClientRect().right - colCoord + 12)
const coordsWithTime = coords?.map((coord, index) => {
return {
coord,
time: this.timeArray[index],
}
})
this.timeCoordsAndTime = coordsWithTime ?? []
},
// Достаем ширину колонки времени и весь массив временой шкалы
getColWidthAndTimeArray() {
this.colWidthAndTimeArray = {
width: this.$refs?.timeCol?.[0]?.clientWidth,
timeArray: this.timeArray,
}
},
async updateSlider() {
await this.$nextTick()
this.slider.update()
this.getDiffBetweenSliderAndSch()
this.getTimeCoordsAndTime()
this.getColWidthAndTimeArray()
this.coordsToHallFunc()
this.scrollToOnline()
},
// Кастом для слайдера кнопка next
next() {
this.slider.translate = this.slider.translate - this.getWidthToSlide()
this.slider.translateTo(this.slider.translate, 250, false)
this.prevOrNextDisabled()
},
// Кастом для слайдера кнопка prev
prev() {
this.slider.translate = this.slider.translate + this.getWidthToSlide()
this.slider.translateTo(this.slider.translate, 250, false)
this.prevOrNextDisabled()
},
// Ширина на которую будет произведен скролл
getWidthToSlide() {
return this.$refs.schWidth.clientWidth / this.scrollLimit
},
prevOrNextDisabled() {
this.nextDisabled = this.slider.translate <= -this.diffBetweenSliderAndSch
this.prevDisabled = this.slider.translate >= 0
},
// Разница между шириной слайдера и секции
getDiffBetweenSliderAndSch() {
if (!this.slider || !this.$refs.schWidth) return
const sliderWidth = this.slider.width
const schWidth = this.$refs.schWidth.clientWidth
this.diffBetweenSliderAndSch = sliderWidth > schWidth ? sliderWidth - schWidth : 0
},
// Скролл до онлайн карточки
async scrollToOnline() {
await this.$nextTick()
if (this.onlineCardId) {
const firstOnlineCardPosition = this.$refs.cards?.find((card) => card.speech.id === this.onlineCardId)?.position
this.slider.translateTo(-firstOnlineCardPosition + this.marginBeforeOnline, 250, false)
}
},
// Кастомный скролл для слайдера
customScroll() {
if (!this.slider) return
if (this.slider.translate <= -this.diffBetweenSliderAndSch) {
this.slider.translate = -this.diffBetweenSliderAndSch
this.customTranslate = -this.diffBetweenSliderAndSch
} else {
this.customTranslate = this.slider.translate
}
},
cardClick(data) {
this.$vfm.show('ZeenSchedule')
this.modalSpeech = data.speech
this.modalHall = data.hall
this.$emit('cardClick', data)
},
cardButtonClick(data) {
if (data.speech.status === 'hold') {
this.$vfm.show('ZeenSchedule')
this.modalSpeech = data.speech
this.modalHall = data.hall
this.$emit('cardButtonClickHold', data)
} else {
this.$emit('cardButtonClick', data)
}
},
hallClick(data) {
this.$emit('hallClick', data)
},
watchSpeech(data) {
this.$emit('watchSpeech', data)
},
addToPersonalSchedule(data) {
this.$emit('addToPersonalSchedule', data)
},
removeFromPersonalSchedule(data) {
this.$emit('removeFromPersonalSchedule', data)
},
coordsToHallFunc() {
const col = this.$refs.timeRow?.getBoundingClientRect().top
const hall = this.$refs.cardsRow?.map((row) => {
return row?.getBoundingClientRect().top - col + this.hallOffset
})
this.coordsToHall = hall ?? []
},
},
computed: {
// получаем координаты для линии показывающее текущее время
onlineLineCoords() {
const timeColWidthAndDiff = this.timeArray.map((time, i) => {
if (i >= this.timeArray.length - 1) return null
const diff = getMinutes(this.timeArray[i + 1]) - getMinutes(time)
return {
width: this.colWidthAndTimeArray?.width / diff,
diff,
}
})
let now = getMinutes(this.date) - this.beginTime
let coord = this.colWidthAndTimeArray?.width * 0.25
timeColWidthAndDiff.forEach((item) => {
switch (true) {
case now > item?.diff:
coord += item?.diff * item?.width
break
case now > 0:
coord += now * item?.width
break
}
now -= item?.diff
})
return coord
},
// получаем массив для временной шкалы
timeArray() {
let speechesTime = this.speechesTime
// Дополнительное время для временной шкалы
this.speechesTimeBeginEnd.forEach((speech) => {
// Разница между началом спича и окончанием
let diff = speech.time_end - speech.time_begin
// Временные отрезки которые будут добавлены между началом спича и окончанием
const timeStep = 5
const bigTimeStep = 10
let count = 1
const toMoreSteps = () => {
diff -= timeStep
++count
speechesTime.push(diff + speech.time_begin)
if (diff >= bigTimeStep && count < this.timeRowStep) {
toMoreSteps()
}
}
switch (true) {
case diff < bigTimeStep && diff > timeStep:
speechesTime.push(bigTimeStep - diff + speech.time_begin)
break
case diff >= bigTimeStep:
toMoreSteps()
}
})
// Удаляем одинаковые временные отрезки и сортируем по возрастанию
speechesTime = [...new Set(speechesTime)].sort((a, b) => a - b)
// Преобразуем минуты в часовой формат
speechesTime = speechesTime.map((step) => toStringTime(step * 60 * 1000, this.timeFormat))
return speechesTime
},
// получаем всех спичей со всех стримов
speeches() {
const arrSpeeches = []
this.streams.forEach((stream) => {
stream.speeches?.forEach((speech) => arrSpeeches.push(speech))
})
return arrSpeeches
},
// получаем id первого по времение онлайн спича из всех стримов
onlineCardId() {
const arrOnlineCards = []
this.speeches.forEach((speech) => {
if (speech.status === 'online') {
arrOnlineCards.push(speech)
}
})
if (arrOnlineCards?.length) {
const minTime = Math.min(...arrOnlineCards.map((card) => getMinutes(card.time_begin)))
const firstOnlineCard = arrOnlineCards.find((card) => {
if (getMinutes(card.time_begin) === minTime) {
return card
}
})
return firstOnlineCard?.id
}
return 0
},
// получаем времена спичей в формате начало спича и конец
speechesTimeBeginEnd() {
const speechesTimeBeginEnd = []
this.speeches.forEach((speech) => {
speechesTimeBeginEnd.push({
time_begin: getMinutes(speech.time_begin),
time_end: getMinutes(speech.time_end),
})
})
return speechesTimeBeginEnd
},
// получаем все времена спичей
speechesTime() {
const speechTimeArr = []
this.speeches.forEach((speech) => {
speechTimeArr.push(getMinutes(speech.time_begin))
speechTimeArr.push(getMinutes(speech.time_end))
})
return speechTimeArr
},
// получаем время начала первого спича
beginTime() {
return Math.min(...this.speechesTime)
},
// получаем время окончания последнего спича
endTime() {
return Math.max(...this.speechesTime)
},
// меняем класс у времени если текущее время больше
timeRowDone() {
const arrTimeDone = this.timeCoordsAndTime.map((item) => {
return this.onlineLineCoords > item.coord ? 'zeen-schedule__time_done' : ''
})
return arrTimeDone ?? []
},
// меняем класс у активного зала
activeHall() {
return this.streams.map((stream) => {
if (stream.id === this.activeStreamId) {
return 'zeen-schedule__hall_active'
}
return undefined
})
},
hallLinkStyles() {
return this.streams.map((_, i) => {
return {top: this.coordsToHall[i] + 'px'}
})
},
// меняем поизицию у линии показывающее текущее время в соответсвии с полученными координатами
onlineLeftSpacing() {
return this.showOnlineLine ? (this.onlineLineCoords ? { left: `${this.onlineLineCoords}px` } : false) : false
},
speechPrefix() {
return 'speech_'
},
speechEvents() {
const {...allEvents} = createEventsFor(this, this.speechPrefix)
delete allEvents.cardClick
delete allEvents.cardButtonClick
return allEvents
},
speechSlots() {
return createSlotsFor(this, this.speechPrefix)
},
modalPrefix() {
return 'modal_'
},
modalEvents() {
const {...allEvents} = createEventsFor(this, this.modalPrefix)
return allEvents
},
modalSlots() {
return createSlotsFor(this, this.modalPrefix)
},
displayedStreams() {
if (this.offSlideToggle) {
return this.streams
}
return this.isOpen ? this.streams : this.streams.slice(0, this.visibleHallsCount)
},
closedHeight() {
if (this.offSlideToggle) {
return null
}
return (275 * this.visibleHallsCount) + 80
}
},
watch: {
onlineCardId() {
setTimeout(() => {
this.updateSlider()
})
},
streams() {
setTimeout(() => {
this.updateSlider()
})
},
},
}
</script>
<style lang="scss">
@import '../../styles/mixins.scss';
:root {
/* Размеры */
--zeen-schedule-header-margin-bottom: 32px;
--zeen-schedule-container-max-width: 100%;
--zeen-schedule-arrows-width: 80%;
--zeen-schedule-col-padding-bottom: 36px;
--zeen-schedule-time-text-size: var(--main-large-size);
--zeen-schedule-time-line-height: 1.5;
--zeen-schedule-time-font-weight: 400;
--zeen-schedule-time-width: 112px;
--zeen-schedule-col-line-size: 750px;
--zeen-schedule-row-height: 274px;
--zeen-schedule-hall-text-size: var(--main-small-text);
--zeen-schedule-hall-line-height: 1.42;
--zeen-schedule-hall-font-weight: 700;
--zeen-schedule-hall-padding-vertical: 8px;
--zeen-schedule-hall-padding-horizontal: 12px;
--zeen-schedule-hall-arrow-size: 16px;
--zeen-schedule-hall-arrow-margin-left: 8px;
--zeen-schedule-hall-left: 50px;
--zeen-schedule-online-img-size: 16px;
--zeen-schedule-card-height: 170px;
--zeen-schedule-online-line-top: 36px;
--zeen-schedule-hall-border-radius: 8px;
--zeen-schedule-hide-button-margin: 8px;
--zeen-schedule-hide-button-size: 16px;
@include phones {
--zeen-schedule-col-padding-bottom: 28px;
--zeen-schedule-row-height: 240px;
--zeen-schedule-time-text-size: 14px;
--zeen-schedule-time-line-height: 1.42;
--zeen-schedule-hall-text-size: 10px;
--zeen-schedule-hall-line-height: 1.6;
--zeen-schedule-hall-padding-vertical: 5px;
--zeen-schedule-hall-padding-horizontal: 32px;
--zeen-schedule-online-img-size: 13px;
--zeen-schedule-card-height: 150px;
--zeen-schedule-online-line-top: 22px;
--zeen-schedule-hall-left: 28px;
}
/* Цвета */
--zeen-schedule-background: var(--main-light);
--zeen-schedule-col-border: var(--gray-1);
--zeen-schedule-time-color: var(--main-color);
--zeen-schedule-time-color-done: var(--gray-2);
--zeen-schedule-col-line: var(--gray-1);
--zeen-schedule-online-line: var(--main-danger-color);
--zeen-schedule-online-img: var(--main-light);
--zeen-schedule-hall: var(--gray-1);
--zeen-schedule-hall-active: var(--main-transparent);
--zeen-schedule-hall-hover: var(--main-transparent);
--zeen-schedule-hall-text: var(--input-main-value-color);
--zeen-schedule-hall-text-active: var(--main-color);
--zeen-schedule-hall-arrow-color: #302e33;
}
</style>
<style scoped lang="scss">
@import '../../styles/mixins.scss';
.zeen-schedule {
background: var(--zeen-schedule-background);
overflow: hidden;
&__top {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--zeen-schedule-header-margin-bottom);
}
&__container {
position: relative;
width: 100%;
max-width: var(--zeen-schedule-container-max-width);
margin-left: auto;
margin-right: auto;
}
&__arrows {
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
display: flex;
justify-content: space-between;
align-items: center;
width: var(--zeen-schedule-arrows-width);
z-index: 10;
@include phones {
display: none;
}
}
&__arrow {
transform: rotateY(180deg);
}
&__main {
box-sizing: border-box;
display: flex;
}
&__wrapper {
position: relative;
}
&__col {
position: relative;
display: flex;
justify-content: flex-start;
align-items: center;
padding: 0;
margin: 0;
list-style-type: none;
padding-bottom: var(--zeen-schedule-col-padding-bottom);
border-bottom: 1px solid var(--zeen-schedule-col-border);
}
&__time {
user-select: none;
position: relative;
font-size: var(--zeen-schedule-time-text-size);
line-height: var(--zeen-schedule-time-line-height);
font-weight: var(--zeen-schedule-time-font-weight);
color: var(--zeen-schedule-time-color);
width: var(--zeen-schedule-time-width);
&:nth-child(2n) {
color: transparent;
&:before {
content: '';
position: absolute;
width: 2px;
height: 10px;
background: var(--zeen-schedule-time-color);
border-radius: 2px;
top: 50%;
transform: translateY(-50%);
left: 25%;
@include phones {
left: 20%;
}
}
}
&_done {
color: var(--zeen-schedule-time-color-done);
&:nth-child(2n) {
&:before {
background: var(--zeen-schedule-time-color-done);
}
}
}
}
&__time-line {
position: absolute;
top: calc(100% + var(--zeen-schedule-col-padding-bottom));
left: 25%;
height: var(--zeen-schedule-col-line-size);
width: 1px;
stroke: var(--zeen-schedule-col-line);
@include phones {
left: 20%;
}
}
&__online-line {
position: absolute;
top: var(--zeen-schedule-online-line-top);
height: 100%;
background: var(--zeen-schedule-online-line);
width: 2px;
}
&__online-circle {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
top: 9px;
left: 50%;
transform: translateX(-50%);
width: 26px;
height: 26px;
background: var(--zeen-schedule-online-line);
border-radius: 100%;
@include phones {
top: 5px;
width: 20px;
height: 20px;
}
}
&__online-img {
display: flex;
justify-content: center;
align-items: center;
fill: var(--zeen-schedule-online-img);
width: var(--zeen-schedule-online-img-size);
height: auto;
}
&__row {
position: relative;
display: flex;
justify-content: flex-start;
align-items: flex-start;
height: var(--zeen-schedule-row-height);
border-bottom: 1px solid var(--zeen-schedule-col-border);
&:last-child {
border-bottom: none;
}
}
&__hall {
position: absolute;
top: 0;
left: var(--zeen-schedule-hall-left);
display: flex;
align-items: center;
padding: var(--zeen-schedule-hall-padding-vertical) var(--zeen-schedule-hall-padding-horizontal);
border-radius: var(--zeen-schedule-hall-border-radius);
background: var(--zeen-schedule-hall);
color: var(--zeen-schedule-hall-text);
font-size: var(--zeen-schedule-hall-text-size);
font-weight: var(--zeen-schedule-hall-font-weight);
line-height: var(--zeen-schedule-hall-line-height);
text-transform: uppercase;
cursor: pointer;
transition: 0.2s;
z-index: 2;
&:hover {
background: var(--zeen-schedule-hall-hover);
}
&_active {
color: var(--zeen-schedule-hall-text-active);
background: var(--zeen-schedule-hall-active);
}
}
&__hall-arrow {
width: var(--zeen-schedule-hall-arrow-size);
height: var(--zeen-schedule-hall-arrow-size);
fill: var(--zeen-schedule-hall-arrow-color);
margin-left: var(--zeen-schedule-hall-arrow-margin-left);
}
&__hall-tooltip-icon {
display: block;
width: var(--zeen-schedule-hall-arrow-size);
height: var(--zeen-schedule-hall-arrow-size);
fill: var(--zeen-schedule-hall-arrow-color);
margin-left: var(--zeen-schedule-hall-arrow-margin-left);
}
&__card {
position: absolute;
left: 0;
bottom: 20px;
z-index: 1;
--zeen-schedule-card-footer-margin-top: 0;
height: var(--zeen-schedule-card-height);
}
&__hide-button {
--button-border-radius: 16px;
display: flex;
justify-content: center;
padding-top: 20px;
width: 100%;
}
&__hide-button-svg {
width: var(--zeen-schedule-hide-button-size);
height: var(--zeen-schedule-hide-button-size);
margin-left: var(--zeen-schedule-hide-button-margin);
transition: 0.2s;
&_open {
transform: rotate(180deg);
}
}
&__popover {
position: relative;
display: flex;
align-items: center;
padding: var(--zeen-schedule-hall-padding-vertical) var(--zeen-schedule-hall-padding-horizontal);
border-radius: var(--zeen-schedule-hall-border-radius);
background: var(--zeen-schedule-hall);
color: var(--zeen-schedule-hall-text);
font-size: var(--zeen-schedule-hall-text-size);
font-weight: var(--zeen-schedule-hall-font-weight);
line-height: var(--zeen-schedule-hall-line-height);
z-index: 1000;
}
}
</style>