@@ -106,14 +106,16 @@ const Video = (props) => {
Video.propTypes = {
className: PropTypes.string,
+ id: PropTypes.string.isRequired,
poster: PropTypes.string.isRequired,
episode: PropTypes.number.isRequired,
+ season: PropTypes.number.isRequired,
title: PropTypes.string.isRequired,
released: PropTypes.instanceOf(Date).isRequired,
isWatched: PropTypes.bool.isRequired,
isUpcoming: PropTypes.bool.isRequired,
progress: PropTypes.number.isRequired,
- onVideoClicked: PropTypes.func
+ onClick: PropTypes.func
};
Video.defaultProps = {
poster: '',
diff --git a/src/routes/Detail/VideosList/Video/styles.less b/src/routes/Detail/VideosList/Video/styles.less
index 1c4b6719a..7864b0843 100644
--- a/src/routes/Detail/VideosList/Video/styles.less
+++ b/src/routes/Detail/VideosList/Video/styles.less
@@ -1,15 +1,6 @@
-.video-container {
- --video-width: 360px;
- --spacing: 8px;
- --title-font-size: 12px;
- --released-date-font-size: 11px;
- --label-font-size: 10px;
- --label-border-width: 2px;
-}
-
.video-container {
width: var(--video-width);
- background-color: var(--color-backgroundlight);
+ background-color: var(--color-surfacedarker60);
.flex-row-container {
display: flex;
@@ -40,21 +31,21 @@
.info-container {
flex: 3;
- min-height: calc(0.2 * var(--video-width));
+ min-height: calc(var(--video-width) * 0.2);
padding: var(--spacing);
display: flex;
flex-direction: column;
justify-content: center;
.title {
- font-size: var(--title-font-size);
- color: var(--color-surfacelighter);
+ line-height: 1.2em;
+ color: var(--color-surfacelight);
word-break: break-all; //Firefox doesn't support { break-word }
word-break: break-word;
}
.released-date {
- font-size: var(--released-date-font-size);
+ font-size: 0.9em;
color: var(--color-surface);
}
@@ -62,13 +53,13 @@
display: flex;
.upcoming-label, .watched-label {
- font-size: var(--label-font-size);
- font-weight: 600;
+ font-size: 0.8em;
+ font-weight: 500;
line-height: 1.5;
- border-width: var(--label-border-width);
+ border-width: calc(var(--spacing) * 0.25);
border-style: solid;
padding: 0 0.6em;
- color: var(--color-surfacelighter);
+ color: var(--color-surfacelight);
}
.upcoming-label {
@@ -82,25 +73,25 @@
}
>:not(:last-child) {
- margin-bottom: calc(0.5 * var(--spacing));
+ margin-bottom: calc(var(--spacing) * 0.5);
}
}
.arrow-container {
- width: calc(0.07 * var(--video-width));
+ width: calc(var(--video-width) * 0.07);
display: flex;
align-items: center;
padding: var(--spacing) var(--spacing) var(--spacing) 0;
.arrow {
width: 100%;
- fill: var(--color-surfacelighter);
+ fill: var(--color-surfacelight);
}
}
}
.progress-container {
- height: calc(0.5 * var(--spacing));
+ height: calc(var(--spacing) * 0.5);
background-color: var(--color-primarydark);
.progress {
@@ -111,6 +102,24 @@
&:hover {
cursor: pointer;
- background-color: var(--color-surfacelighter20);
+ background-color: var(--color-surfacedarker);
+
+ .info-container {
+ .title {
+ color: var(--color-surfacelighter);
+ }
+
+ .label-container {
+ .upcoming-label, .watched-label {
+ color: var(--color-surfacelighter);
+ }
+ }
+ }
+
+ .arrow-container {
+ .arrow {
+ fill: var(--color-surfacelighter);
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/routes/Detail/VideosList/VideosList.js b/src/routes/Detail/VideosList/VideosList.js
index 3cc1be171..c2559ad91 100644
--- a/src/routes/Detail/VideosList/VideosList.js
+++ b/src/routes/Detail/VideosList/VideosList.js
@@ -1,6 +1,8 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
+import classnames from 'classnames';
import Icon from 'stremio-icons/dom';
+import { Popup } from 'stremio-common';
import Video from './Video';
import styles from './styles';
@@ -8,20 +10,25 @@ class VideosList extends Component {
constructor(props) {
super(props);
+ this.seasonsPopupRef = React.createRef();
this.seasons = this.props.videos.map((video) => video.season)
.filter((season, index, seasons) => seasons.indexOf(season) === index);
this.state = {
- selectedSeason: this.seasons[0]
+ selectedSeason: this.seasons[0],
+ selectedVideoId: 0,
+ seasonsPopupOpen: false
}
}
changeSeason = (event) => {
- this.setState({ selectedSeason: parseInt(event.target.value) });
+ this.setState({ selectedSeason: parseInt(event.currentTarget.dataset.season) });
+ this.seasonsPopupRef.current && this.seasonsPopupRef.current.close();
}
shouldComponentUpdate(nextProps, nextState) {
- return nextState.selectedSeason !== this.state.selectedSeason;
+ return nextState.selectedSeason !== this.state.selectedSeason ||
+ nextState.seasonsPopupOpen !== this.state.seasonsPopupOpen;
}
onPrevButtonClicked = () => {
@@ -34,20 +41,45 @@ class VideosList extends Component {
this.setState({ selectedSeason: this.seasons[nextSeasonIndex] });
}
+ onSeasonsPopupOpen = () => {
+ this.setState({ seasonsPopupOpen: true });
+ }
+
+ onSeasonsPopupClose = () => {
+ this.setState({ seasonsPopupOpen: false });
+ }
+
+ onClick = (event) => {
+ this.setState({ selectedVideoId: event.currentTarget.dataset.videoId });
+ console.log(event.currentTarget.dataset.videoId);
+ }
+
render() {
return (
-
+
-
- {this.seasons.map((season) =>
-
- {season}
-
- )}
-
+
+
+
+
Season
+
{this.state.selectedSeason}
+
+
+
+
+
+ {this.seasons.map((season) =>
+
+ )}
+
+
+
@@ -58,13 +90,16 @@ class VideosList extends Component {
.map((video) =>
)}
@@ -74,6 +109,7 @@ class VideosList extends Component {
}
VideosList.propTypes = {
+ className: PropTypes.string,
videos: PropTypes.arrayOf(PropTypes.object).isRequired
};
VideosList.defaultProps = {
diff --git a/src/routes/Detail/VideosList/styles.less b/src/routes/Detail/VideosList/styles.less
index 41f242d3b..f52f596d6 100644
--- a/src/routes/Detail/VideosList/styles.less
+++ b/src/routes/Detail/VideosList/styles.less
@@ -1,24 +1,69 @@
.videos-list-container {
- --scroll-container-width: 392px;
- --seasons-bar-height: 50px;
- --spacing: 8px;
-}
-
-.videos-list-container {
- height: 100%;
- display: inline-flex;
+ width: calc(var(--video-width) + var(--spacing) * 6);
+ display: flex;
flex-direction: column;
- background: var(--color-background);
+ align-items: center;
+ background: var(--color-backgrounddarker40);
.seasons-bar {
- height: var(--seasons-bar-height);
+ height: calc(var(--video-width) * 0.14);
+ width: 100%;
display: flex;
justify-content: space-between;
margin-bottom: var(--spacing);
- .button-container {
- width: calc(1.5 * var(--seasons-bar-height));
+ .season-bar-button {
cursor: pointer;
+ width: calc(var(--video-width) * 0.6);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: var(--spacing);
+ color: var(--color-surfacelight);
+
+ .season-label {
+ max-width: 8em;
+ max-height: 2.4em;
+ font-size: 1.2em;
+ line-height: 1.2em;
+ text-align: end;
+ overflow: hidden;
+ }
+
+ .season-number {
+ margin: 0 calc(var(--spacing) * 1.5) 0 var(--spacing);
+ font-size: 1.2em;
+ line-height: 1.2em;
+ }
+
+ .icon {
+ width: calc(var(--video-width) * 0.04);
+ height: calc(var(--video-width) * 0.04);
+ fill: var(--color-surfacelight);
+ }
+
+ &:hover {
+ color: var(--color-surfacelighter);
+ background-color: var(--color-surfacedarker60);
+
+ .icon {
+ fill: var(--color-surfacelighter);
+ }
+ }
+
+ &:global(.active) {
+ color: var(--color-backgrounddarker);
+ background-color: var(--color-surfacelighter);
+
+ .icon {
+ fill: var(--color-backgrounddarker);
+ }
+ }
+ }
+
+ .button-container {
+ cursor: pointer;
+ width: calc(var(--video-width) * 0.2);
display: flex;
align-items: center;
justify-content: center;
@@ -26,18 +71,22 @@
.button-icon {
width: 60%;
height: 60%;
- fill: var(--color-surfacelighter);
+ fill: var(--color-surfacelight);
}
&:hover {
- background-color: var(--color-surfacelighter20);
+ background-color: var(--color-surfacedarker60);
+
+ .button-icon {
+ fill: var(--color-surfacelighter);
+ }
}
}
}
.scroll-container {
flex: 1;
- width: var(--scroll-container-width);
+ width: calc(var(--video-width) + var(--spacing) * 4);
padding: 0 calc(2 * var(--spacing));
margin: 0 var(--spacing);
overflow-y: auto;
@@ -49,14 +98,54 @@
}
.scroll-container::-webkit-scrollbar {
- width: var(--spacing);
+ width: var(--spacing) !important;
}
.scroll-container::-webkit-scrollbar-thumb {
- background-color: var(--color-secondarylighter80);
+ background-color: var(--color-secondarylighter);
}
.scroll-container::-webkit-scrollbar-track {
- background-color: var(--color-backgroundlight);
+ background-color: var(--color-backgroundlighter);
+ }
+}
+
+:global(.detail-popup-container) {
+ --border-color: var(--color-backgrounddarker80);
+
+ .popup-content {
+ width: calc(var(--video-width) * 0.6);
+ background-color: var(--color-surfacelighter);
+
+ .season {
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ width: 100%;
+ padding: calc(var(--spacing) * 1.5);
+ font-size: 1.2em;
+ color: var(--color-backgrounddark);
+
+ .season-label {
+ max-height: 2.4em;
+ line-height: 1.2em;
+ overflow: hidden;
+ }
+
+ .season-number {
+ margin-left: var(--spacing);
+ line-height: 1.2em;
+ }
+
+ &.selected-season {
+ color: var(--color-surfacelighter);
+ background-color: var(--color-primarydark);
+ }
+
+ &:hover {
+ color: var(--color-surfacelighter);
+ background-color: var(--color-primarylight);
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/routes/Detail/styles.less b/src/routes/Detail/styles.less
new file mode 100644
index 000000000..c45e3e2fa
--- /dev/null
+++ b/src/routes/Detail/styles.less
@@ -0,0 +1,175 @@
+.detail-container, :global(.detail-popup-container) {
+ --spacing: 8px;
+ --action-button-width: 80px;
+ --video-width: 360px;
+ --stream-width: 360px;
+ font-size: 12px;
+}
+
+.detail-container {
+ position: relative;
+ z-index: 0;
+ width: 100%;
+ height: 100%;
+ background-size: cover;
+ background-position: center;
+ background-repeat: no-repeat;
+
+ .overlay-container {
+ position: absolute;
+ z-index: 0;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: var(--color-backgrounddarker60);
+ }
+
+ .info-container {
+ position: absolute;
+ z-index: 1;
+ top: 0;
+ left: 0;
+ right: 40%;
+ bottom: 0;
+ padding: calc(var(--spacing) * 3);
+
+ .logo {
+ display: block;
+ height: calc(var(--action-button-width) * 1.2);
+ object-fit: contain;
+ }
+
+ .logo-error {
+ display: none;
+ }
+
+ .duration {
+ display: inline-block;
+ max-width: 45%;
+ margin-right: 1.2em;
+ font-size: 1.15em;
+ overflow: hidden;
+ white-space: pre;
+ text-overflow: ellipsis;
+ color: var(--color-surfacelight);
+ }
+
+ .release-info {
+ display: inline-block;
+ max-width: 45%;
+ font-size: 1.15em;
+ overflow: hidden;
+ white-space: pre;
+ text-overflow: ellipsis;
+ color: var(--color-surfacelight);
+ }
+
+ .name {
+ max-height: 3em;
+ overflow: hidden;
+ overflow-wrap: break-word;
+ font-size: 1.5em;
+ line-height: 1.5;
+ color: var(--color-surfacelight);
+ }
+
+ .description {
+ max-height: 10.5em;
+ overflow: hidden;
+ overflow-wrap: break-word;
+ line-height: 1.5;
+ color: var(--color-surfacelight);
+ }
+
+ .section-container {
+ max-height: 3.2em;
+ overflow: hidden;
+
+ .title {
+ margin-bottom: 0.3em;
+ font-size: 1.15em;
+ color: var(--color-surface);
+ }
+
+ .link {
+ display: none;
+ max-width: 100%;
+ padding: 0.3em 0.6em;
+ font-size: 1.15em;
+ overflow: hidden;
+ white-space: pre;
+ text-overflow: ellipsis;
+ color: var(--color-surfacelight);
+ cursor: pointer;
+
+ &:hover {
+ color: var(--color-surfacelighter);
+ background-color: var(--color-surface40);
+ }
+
+ &:nth-child(-n+6) {
+ display: inline-block;
+ }
+ }
+ }
+
+ .action-buttons-container {
+ position: absolute;
+ left: calc(var(--spacing) * 3);
+ bottom: calc(var(--spacing) * 3);
+
+ .action-button-container {
+ cursor: pointer;
+ width: var(--action-button-width);
+ height: var(--action-button-width);
+ display: inline-flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ text-align: center;
+
+ .icon {
+ height: 30%;
+ margin: 10% 0;
+ fill: var(--color-surfacelight);
+ }
+
+ .label {
+ height: 2.4em;
+ padding: 0 1em;
+ overflow-wrap: break-word;
+ overflow: hidden;
+ font-size: 1.05em;
+ line-height: 1.2em;
+ color: var(--color-surfacelight);
+ }
+
+ &:hover {
+ background-color: var(--color-surfacedarker60);
+
+ .icon {
+ fill: var(--color-surfacelighter);
+ }
+
+ .label {
+ color: var(--color-surfacelighter);
+ }
+ }
+ }
+ }
+
+ >:not(:last-child) {
+ margin-bottom: calc(var(--spacing) * 1.5);
+ }
+ }
+
+ .videos-list {
+ position: absolute;
+ z-index: 2;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ padding: calc(3 * var(--spacing)) 0;
+ }
+}
\ No newline at end of file
diff --git a/stories/index.stories.js b/stories/index.stories.js
index 996e11312..2401ba71f 100644
--- a/stories/index.stories.js
+++ b/stories/index.stories.js
@@ -1,6 +1,7 @@
import React from 'react';
import { storiesOf } from '@storybook/react';
-import { Addon, Checkbox, LibraryItemList, MetaItem, ShareAddon, UserPanel } from 'stremio-common';
+import { Checkbox, LibraryItemList, MetaItem, ShareAddon, UserPanel } from 'stremio-common';
+import Addon from '../src/routes/Addons/Addon';
import Stream from '../src/routes/Detail/StreamsList/Stream';
import Video from '../src/routes/Detail/VideosList/Video';
import VideosList from '../src/routes/Detail/VideosList';
@@ -42,7 +43,6 @@ storiesOf('Addon', module)
isInstalled={false}
types={['Movies', 'Series']}
description={'Find where to stream your favourite movies and shows amongst iTunes, Hulu, Amazon and other UK/US services.'}
- urls={['http://nfxaddon.strem.io/stremioget', 'http://127.0.0.1:11470/addons/com.stremio.subtitles/stremioget', 'http://127.0.0.1:11470/addons/com.stremio.localfiles/stremioget']}
/>
))
@@ -54,7 +54,6 @@ storiesOf('Addon', module)
isInstalled={true}
types={['Movies', 'Series']}
description={'Watch your favourite YouTube channels ad-free and get notified when they upload new videos.'}
- urls={['https://channels.strem.io/stremioget/stremio/v1', 'https://channels.strem.io/stremioget/stremio/v1']}
/>
))
@@ -67,7 +66,6 @@ storiesOf('Addon', module)
isInstalled={true}
types={['Channels', 'Videos']}
description={'Watch your favourite YouTube channels ad-free and get notiour favourite YouTube channels ad-free and get notiour favourite YouTube channels ad-free and get notiour favourite YouTube channels ad-free and get notiour favourite YouTube channels ad-free and get notiourfavourite YouTube channels ad-free and get notiour favourite YouTube channels ad-free and get notiourfavourite YouTube channels ad-free and get notiour favourite YouTube channels ad-free and get notiour favourite YouTube channels ad-free and get notified when they upload new videos.'}
- urls={['https://channels.strem.io/stremioget/stremio/v1', 'https://channels.strem.io/stremioget/stremio/v1']}
/>
))
@@ -79,7 +77,6 @@ storiesOf('Addon', module)
isInstalled={false}
types={['Movies', 'Series']}
description={'Watch your favourite YouTube channels ad-free and get notified when they upload new videos.'}
- urls={['https://channels.strem.io/stremioget/stremio/v1channels.strem.io/stremioget/stremio/v1channels.strem.io/stremioget/stremio/v1', 'https://channels.strem.io/stremioget/stremio/v1', 'http://127.0.0.1:11470/addons/com.stremio.subtitles/stremioget', 'https://channels.strem.io/stremioget/stremio/v1']}
/>