mirror of
https://github.com/Stremio/stremio-web.git
synced 2026-04-19 01:22:11 +00:00
calendar improved
This commit is contained in:
parent
e561a878e2
commit
e8ef50c790
2 changed files with 155 additions and 134 deletions
|
|
@ -5,8 +5,8 @@ import { Input } from 'stremio-common';
|
|||
import Icon from 'stremio-icons/dom';
|
||||
import styles from './styles';
|
||||
|
||||
const days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
|
||||
const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
|
||||
const DAYS = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
|
||||
const MONTHS = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
|
||||
|
||||
class Calendar extends Component {
|
||||
constructor(props) {
|
||||
|
|
@ -47,32 +47,30 @@ class Calendar extends Component {
|
|||
|
||||
changeDate = (event) => {
|
||||
const date = new Date(parseInt(event.currentTarget.dataset.date));
|
||||
|
||||
var videosIds = this.props.metaItems
|
||||
.map((metaitem) => metaitem.videos
|
||||
.filter((video) => video.released.getFullYear() === this.state.date.getFullYear() && video.released.getMonth() === this.state.date.getMonth() && video.released.getDate() === date.getDate())
|
||||
.map((video) => video.id))
|
||||
.filter((videos) => videos.length > 0);
|
||||
|
||||
if (videosIds.length > 0) {
|
||||
this.setState({ date, videoId: videosIds[0][0] });
|
||||
} else {
|
||||
this.setState({ date });
|
||||
for (let metaItem of this.props.metaItems) {
|
||||
let video = metaItem.videos.find((video) => {
|
||||
return video.released.getFullYear() === date.getFullYear() && video.released.getMonth() === date.getMonth() && video.released.getDate() === date.getDate();
|
||||
});
|
||||
if (video) {
|
||||
this.setState({ date, videoId: video.id });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({ date, videoId: '' });
|
||||
}
|
||||
|
||||
showVideoInfo = (event) => {
|
||||
event.stopPropagation();
|
||||
for (let metaItem of this.props.metaItems) {
|
||||
let video = metaItem.videos.find((video) => video.id == event.currentTarget.dataset.videoId);
|
||||
if (video) {
|
||||
this.setState({ date: new Date(video.released), videoId: video.id });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var selectedVideoDate = this.props.metaItems
|
||||
.map((metaitem) => metaitem.videos
|
||||
.filter((video) => video.id == event.currentTarget.dataset.videoId))
|
||||
.reduce((result, videoDates) => {
|
||||
result = result.concat(videoDates);
|
||||
return result;
|
||||
}, [])[0].released;
|
||||
|
||||
this.setState({ videoId: event.currentTarget.dataset.videoId, date: new Date(selectedVideoDate) });
|
||||
this.setState({ date: new Date(), videoId: '' });
|
||||
}
|
||||
|
||||
getMonthInfo = (date) => {
|
||||
|
|
@ -92,61 +90,66 @@ class Calendar extends Component {
|
|||
}
|
||||
|
||||
renderMonthButton(date) {
|
||||
return (
|
||||
date.getMonth() === this.state.date.getMonth() ?
|
||||
<div className={styles['month']}>{months[date.getMonth()]}</div>
|
||||
:
|
||||
<Input className={styles['month']} type={'button'} data-date={date.getTime()} onClick={this.changeDate}>{months[date.getMonth()]}</Input>
|
||||
);
|
||||
return date.getMonth() === this.state.date.getMonth() ?
|
||||
<div className={styles['month']}>{MONTHS[date.getMonth()]}</div>
|
||||
:
|
||||
<Input className={styles['month']} type={'button'} data-date={date.getTime()} onClick={this.changeDate}>{MONTHS[date.getMonth()]}</Input>
|
||||
}
|
||||
|
||||
renderMonthWeeks = () => {
|
||||
renderCalendar = (videosForMonth) => {
|
||||
const { padsCount, daysCount, weeksCount } = this.getMonthInfo(this.state.date);
|
||||
var weeks = [];
|
||||
|
||||
for (let week = 0; week < weeksCount; week++) {
|
||||
const weeks = [];
|
||||
for (let weekNumber = 0; weekNumber < weeksCount; weekNumber++) {
|
||||
weeks.push(
|
||||
<div key={week} className={styles['week']}>
|
||||
{this.renderMonthDays(week, weeksCount, padsCount, daysCount)}
|
||||
<div key={weekNumber} className={styles['week']}>
|
||||
{this.renderMonthDays(weekNumber, padsCount, daysCount, weeksCount, videosForMonth)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return weeks;
|
||||
|
||||
return (
|
||||
<div className={styles['month-days']}>
|
||||
<div className={styles['week-days']}>
|
||||
{DAYS.map((day) => <div key={day} className={styles['day']}>{day}</div>)}
|
||||
</div>
|
||||
{weeks}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderMonthDays = (week, weeksCount, padsCount, daysCount) => {
|
||||
var days = [];
|
||||
|
||||
renderMonthDays = (weekNumber, padsCount, daysCount, weeksCount, videosForMonth) => {
|
||||
const today = new Date();
|
||||
const days = [];
|
||||
for (let day = 0; day < 7; day++) {
|
||||
days.push(
|
||||
day < padsCount && week === 0
|
||||
day < padsCount && weekNumber === 0
|
||||
?
|
||||
<div key={day} className={styles['pad']} />
|
||||
:
|
||||
(week * 7) + (day - padsCount) < daysCount
|
||||
(weekNumber * 7) + (day - padsCount) < daysCount
|
||||
?
|
||||
<Input key={day}
|
||||
className={classnames(styles['day'], { [styles['selected']]: this.state.date.getDate() === (week * 7) + (day - padsCount + 1) })}
|
||||
className={classnames(styles['day'], { [styles['selected']]: this.state.date.getDate() === (weekNumber * 7) + (day - padsCount + 1) })}
|
||||
type={'button'}
|
||||
data-date={new Date(this.state.date.getFullYear(), this.state.date.getMonth(), (week * 7) + (day - padsCount + 1)).getTime()}
|
||||
data-date={new Date(this.state.date.getFullYear(), this.state.date.getMonth(), (weekNumber * 7) + (day - padsCount + 1)).getTime()}
|
||||
onClick={this.changeDate}
|
||||
>
|
||||
<div className={styles['date-container']}>
|
||||
<div className={classnames(styles['date'], { [styles['today']]: new Date().toDateString() === new Date(this.state.date.getFullYear(), this.state.date.getMonth(), (week * 7) + day - padsCount + 1).toDateString() })}>{(week * 7) + (day - padsCount + 1)}</div>
|
||||
<div className={classnames(styles['date'], { [styles['today']]: this.state.date.getFullYear() === today.getFullYear() && this.state.date.getMonth() === today.getMonth() && ((weekNumber * 7) + day - padsCount + 1) === today.getDate() })}>{(weekNumber * 7) + (day - padsCount + 1)}</div>
|
||||
</div>
|
||||
<div className={classnames(styles['videos'], { [styles['small']]: weeksCount === 6 }, { [styles['big']]: weeksCount === 4 })}>
|
||||
{this.props.metaItems
|
||||
.map((metaitem) => metaitem.videos
|
||||
.filter((video) => video.released.getFullYear() === this.state.date.getFullYear() && video.released.getMonth() === this.state.date.getMonth() && video.released.getDate() === (week * 7) + (day - padsCount + 1))
|
||||
<div className={styles['videos']}>
|
||||
{
|
||||
videosForMonth
|
||||
.filter((video) => video.released.getDate() === (weekNumber * 7) + (day - padsCount + 1))
|
||||
.map((video) =>
|
||||
<div key={video.id}
|
||||
style={{ backgroundImage: `url('${metaitem.poster}')` }}
|
||||
className={classnames(styles['poster'], { [styles['past']]: video.released.getTime() < new Date().getTime() })}
|
||||
style={{ backgroundImage: `url('${video.metaPoster}')` }}
|
||||
className={classnames(styles['poster'], { [styles['past']]: video.released.getTime() < today.getTime() })}
|
||||
data-video-id={video.id}
|
||||
onClick={this.showVideoInfo}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
}
|
||||
</div>
|
||||
</Input>
|
||||
:
|
||||
|
|
@ -156,16 +159,99 @@ class Calendar extends Component {
|
|||
return days;
|
||||
}
|
||||
|
||||
renderSideBar = (videoDates, videosForMonth) => {
|
||||
const today = new Date();
|
||||
|
||||
return (
|
||||
<div ref={this.videosScrollContainerRef} className={styles['videos-scroll-container']}>
|
||||
{
|
||||
videoDates.length > 0
|
||||
?
|
||||
videoDates.map((videoDate) =>
|
||||
<div key={videoDate.getDate()}
|
||||
ref={videoDate.getDate() === this.state.date.getDate() ? this.selectedDateVideosContainerRef : null}
|
||||
className={classnames(styles['videos-container'], { [styles['selected']]: videoDate.getDate() === this.state.date.getDate() })}
|
||||
data-date={new Date(this.state.date.getFullYear(), this.state.date.getMonth(), videoDate.getDate()).getTime()}
|
||||
onClick={this.changeDate}
|
||||
>
|
||||
<div className={styles['date']}>
|
||||
{MONTHS[this.state.date.getMonth()].slice(0, 3)} {videoDate.getDate()}
|
||||
</div>
|
||||
{
|
||||
videosForMonth
|
||||
.filter((video) => video.released.getDate() === videoDate.getDate())
|
||||
.map((video) =>
|
||||
<Input key={video.id}
|
||||
className={classnames(styles['video'], { [styles['selected']]: this.state.videoId === video.id }, { [styles['today']]: video.released.getFullYear() === today.getFullYear() && video.released.getMonth() === today.getMonth() && video.released.getDate() === today.getDate() && this.state.videoId !== video.id })}
|
||||
type={'button'}
|
||||
data-video-id={video.id}
|
||||
onClick={this.showVideoInfo}
|
||||
>
|
||||
<div className={styles['main-info']}>
|
||||
<div className={styles['meta-item-name']}>
|
||||
{video.metaName}
|
||||
</div>
|
||||
{
|
||||
video.season || video.episode
|
||||
?
|
||||
<div className={styles['video-number']}>
|
||||
S{video.season} E{video.episode}
|
||||
</div>
|
||||
:
|
||||
null
|
||||
}
|
||||
</div>
|
||||
<div className={styles['name']}>
|
||||
{video.name}
|
||||
</div>
|
||||
{
|
||||
video.description
|
||||
?
|
||||
<div className={styles['description']}>
|
||||
{video.description}
|
||||
</div>
|
||||
:
|
||||
null
|
||||
}
|
||||
<Input className={styles['watch-button-container']} type={'link'} href={video.released.getTime() < today.getTime() ? '#/player' : '#/detail'}>
|
||||
<div className={styles['watch-button']}>
|
||||
<Icon className={styles['icon']} icon={'ic_play'} />
|
||||
<div className={styles['label']}>{video.released.getTime() < today.getTime() ? 'WATCH NOW' : 'SHOW'}</div>
|
||||
</div>
|
||||
</Input>
|
||||
</Input>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
)
|
||||
:
|
||||
null
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const videoDates = this.props.metaItems
|
||||
.map((metaitem) => metaitem.videos
|
||||
.filter((video) => video.released.getFullYear() === this.state.date.getFullYear() && video.released.getMonth() === this.state.date.getMonth()))
|
||||
const videosForMonth = this.props.metaItems
|
||||
.map((mItem) => {
|
||||
return mItem.videos
|
||||
.filter((video) => {
|
||||
return video.released.getFullYear() === this.state.date.getFullYear() && video.released.getMonth() === this.state.date.getMonth();
|
||||
})
|
||||
.map((video) => ({
|
||||
...video,
|
||||
metaPoster: mItem.poster,
|
||||
metaName: mItem.name
|
||||
}));
|
||||
})
|
||||
.filter((videos) => videos.length > 0)
|
||||
.map((videos) => videos.map((video) => video.released))
|
||||
.reduce((result, videoDates) => {
|
||||
result = result.concat(videoDates);
|
||||
.reduce((result, videos) => {
|
||||
result = result.concat(videos);
|
||||
return result;
|
||||
}, [])
|
||||
}, []);
|
||||
|
||||
const videoDates = videosForMonth
|
||||
.map((video) => video.released)
|
||||
.filter((date, index, dates) => {
|
||||
for (var i = 0; i < dates.length; i++) {
|
||||
if (dates[i].getTime() === date.getTime()) {
|
||||
|
|
@ -187,66 +273,9 @@ class Calendar extends Component {
|
|||
{this.renderMonthButton(this.state.date)}
|
||||
{this.renderMonthButton(new Date(this.state.date.getFullYear(), this.state.date.getMonth() + 1), 1)}
|
||||
</div>
|
||||
<div className={styles['month-days']}>
|
||||
<div className={styles['week-days']}>
|
||||
{days.map((day) => <div key={day} className={styles['day']}>{day}</div>)}
|
||||
</div>
|
||||
{this.renderMonthWeeks()}
|
||||
</div>
|
||||
</div>
|
||||
<div ref={this.videosScrollContainerRef} className={styles['videos-scroll-container']}>
|
||||
{
|
||||
videoDates.length > 0
|
||||
?
|
||||
videoDates.map((videoDate) =>
|
||||
<div key={videoDate.getDate()}
|
||||
ref={videoDate.getDate() === this.state.date.getDate() ? this.selectedDateVideosContainerRef : null}
|
||||
className={classnames(styles['videos-container'], { [styles['selected']]: videoDate.getDate() === this.state.date.getDate() })}
|
||||
data-date={new Date(this.state.date.getFullYear(), this.state.date.getMonth(), videoDate.getDate()).getTime()}
|
||||
onClick={this.changeDate}
|
||||
>
|
||||
<div className={styles['date']}>
|
||||
{months[this.state.date.getMonth()].slice(0, 3)} {videoDate.getDate()}
|
||||
</div>
|
||||
{this.props.metaItems
|
||||
.map((metaitem) => metaitem.videos
|
||||
.filter((video) => video.released.getFullYear() === this.state.date.getFullYear() && video.released.getMonth() === this.state.date.getMonth() && video.released.getDate() === videoDate.getDate())
|
||||
.map((video) =>
|
||||
<Input key={video.id}
|
||||
className={classnames(styles['video'], { [styles['selected']]: this.state.videoId === video.id }, { [styles['today']]: new Date().toDateString() === new Date(video.released.getFullYear(), video.released.getMonth(), videoDate.getDate()).toDateString() && this.state.videoId !== video.id })}
|
||||
type={'button'}
|
||||
data-video-id={video.id}
|
||||
onClick={this.showVideoInfo}
|
||||
>
|
||||
<div className={styles['main-info']}>
|
||||
<div className={styles['meta-item-name']}>
|
||||
{metaitem.name}
|
||||
</div>
|
||||
<div className={styles['video-number']}>
|
||||
S{video.season} E{video.episode}
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles['name']}>
|
||||
{video.name}
|
||||
</div>
|
||||
<div className={styles['description']}>
|
||||
{video.description}
|
||||
</div>
|
||||
<Input className={styles['watch-button-container']} type={'link'} href={video.released.getTime() < new Date().getTime() ? '#/player' : '#/detail'}>
|
||||
<div className={styles['watch-button']}>
|
||||
<Icon className={styles['icon']} icon={'ic_play'} />
|
||||
<div className={styles['label']}>{video.released.getTime() < new Date().getTime() ? 'WATCH NOW' : 'SHOW'}</div>
|
||||
</div>
|
||||
</Input>
|
||||
</Input>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
:
|
||||
null
|
||||
}
|
||||
{this.renderCalendar(videosForMonth)}
|
||||
</div>
|
||||
{this.renderSideBar(videoDates, videosForMonth)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,14 +85,13 @@
|
|||
|
||||
.day {
|
||||
display: table-cell;
|
||||
border: var(--focusable-border-size) solid transparent;
|
||||
border: calc(var(--focusable-border-size) * 0.5) solid transparent;
|
||||
background-color: var(--color-backgroundlighter);
|
||||
cursor: pointer;
|
||||
|
||||
.date-container {
|
||||
margin: calc(var(--spacing) * 0.5);
|
||||
width: calc(var(--episodes-height) * 0.64);
|
||||
height: calc(var(--episodes-height) * 0.64);
|
||||
flex: 1;
|
||||
|
||||
.date {
|
||||
width: 100%;
|
||||
|
|
@ -104,7 +103,6 @@
|
|||
color: var(--color-secondarylighter);
|
||||
|
||||
&.today {
|
||||
border-radius: 50%;
|
||||
color: var(--color-surfacelighter);
|
||||
background-color: var(--color-primary);
|
||||
}
|
||||
|
|
@ -112,15 +110,13 @@
|
|||
}
|
||||
|
||||
.videos {
|
||||
margin: var(--focusable-border-size);
|
||||
height: var(--episodes-height);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
.poster {
|
||||
margin-right: var(--focusable-border-size);
|
||||
display: none;
|
||||
width: 25%;
|
||||
flex: calc(1 / var(--poster-shape-ratio));
|
||||
height: 100%;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
|
|
@ -133,18 +129,14 @@
|
|||
&:nth-child(-n+4) {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
&.small {
|
||||
height: calc(var(--episodes-height) * 0.64);
|
||||
}
|
||||
|
||||
&.big {
|
||||
height: calc(var(--episodes-height) * 1.54);
|
||||
&:not(:last-child) {
|
||||
margin-right: var(--focusable-border-size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:focus {
|
||||
&:hover, &:focus {
|
||||
border-color: var(--color-surfacelighter);
|
||||
}
|
||||
|
||||
|
|
@ -240,13 +232,13 @@
|
|||
justify-content: center;
|
||||
|
||||
.icon {
|
||||
margin-right: 8%;
|
||||
width: 8%;
|
||||
margin-right: 1em;
|
||||
width: 1em;
|
||||
fill: var(--color-surfacelight);
|
||||
}
|
||||
|
||||
.label {
|
||||
max-width: 84%;
|
||||
max-width: 9em;
|
||||
word-break: break-all; //Firefox doesn't support { break-word }
|
||||
word-break: break-word;
|
||||
color: var(--color-surfacelight);
|
||||
|
|
|
|||
Loading…
Reference in a new issue