Merge branch 'master' of github.com:Stremio/stremio-web into color-picker

This commit is contained in:
svetlagasheva 2019-08-30 10:08:59 +03:00
commit db784c73a2
29 changed files with 275 additions and 379 deletions

View file

@ -16,6 +16,8 @@ const MainNavBar = ({ className }) => {
backButton={false}
tabs={TABS}
searchBar={true}
addonsButton={true}
fullscreenButton={true}
navMenu={true}
/>
);

View file

@ -26,7 +26,7 @@ const MetaPreview = ({ className, compact = false, id, type, name, logo = '', ba
return Array.isArray(genres) ?
genres.map((genre) => ({
label: genre,
href: `#/discover/${type}//${genre}`
href: `#/discover/${type}//?genre=${genre}`
}))
:
[];

View file

@ -3,7 +3,6 @@
z-index: 0;
display: flex;
flex-direction: column;
background-color: var(--color-backgrounddarker);
&.compact {
.meta-info {
@ -16,8 +15,7 @@
justify-content: space-evenly;
.duration, .release-info {
margin-left: 0.4em;
margin-right: 0.4em;
margin: 1rem 0.4rem;
}
}
}
@ -42,8 +40,7 @@
height: 100%;
object-fit: cover;
object-position: center;
opacity: 0.8;
filter: blur(5px);
filter: blur(5px) brightness(80%);
}
}
@ -104,9 +101,9 @@
.action-button {
flex: none;
width: 6.5rem;
height: 6.5rem;
margin: 1rem 1rem 1rem 0;
width: 6rem;
height: 6rem;
margin: 1rem 0;
}
}
}

View file

@ -0,0 +1,20 @@
const React = require('react');
const PropTypes = require('prop-types');
const classnames = require('classnames');
const Icon = require('stremio-icons/dom');
const Button = require('stremio/common/Button');
const styles = require('./styles');
const AddonsButton = ({ className }) => {
return (
<Button className={classnames(className, styles['addons-button-container'])} href={'#/addons'} tabIndex={-1}>
<Icon className={styles['icon']} icon={'ic_addons'} />
</Button>
);
};
AddonsButton.propTypes = {
className: PropTypes.string
};
module.exports = AddonsButton;

View file

@ -0,0 +1,3 @@
const AddonsButton = require('./AddonsButton');
module.exports = AddonsButton;

View file

@ -0,0 +1,17 @@
.addons-button-container {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
&:hover {
background-color: var(--color-secondary);
}
.icon {
flex: none;
width: 1.6rem;
height: 1.6rem;
fill: var(--color-surfacelighter);
}
}

View file

@ -0,0 +1,22 @@
const React = require('react');
const PropTypes = require('prop-types');
const classnames = require('classnames');
const Icon = require('stremio-icons/dom');
const Button = require('stremio/common/Button');
const useFullscreen = require('stremio/common/useFullscreen');
const styles = require('./styles');
const FullscreenButton = ({ className }) => {
const [fullscreen, requestFullscreen, exitFullscreen] = useFullscreen();
return (
<Button className={classnames(className, styles['fullscreen-button-container'])} title={fullscreen ? 'Exit Fullscreen' : 'Enter Fullscreen'} onClick={fullscreen ? exitFullscreen : requestFullscreen} tabIndex={-1}>
<Icon className={styles['icon']} icon={fullscreen ? 'ic_exit_fullscreen' : 'ic_fullscreen'} />
</Button>
);
};
FullscreenButton.propTypes = {
className: PropTypes.string
};
module.exports = FullscreenButton;

View file

@ -0,0 +1,3 @@
const FullscreenButton = require('./FullscreenButton');
module.exports = FullscreenButton;

View file

@ -0,0 +1,17 @@
.fullscreen-button-container {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
&:hover {
background-color: var(--color-secondary);
}
.icon {
flex: none;
width: 1.6rem;
height: 1.6rem;
fill: var(--color-surfacelighter);
}
}

View file

@ -1,12 +1,14 @@
const React = require('react');
const PropTypes = require('prop-types');
const classnames = require('classnames');
const NavBarButton = require('./NavBarButton');
const NavTabButton = require('./NavTabButton');
const SearchBar = require('./SearchBar');
const AddonsButton = require('./AddonsButton');
const FullscreenButton = require('./FullscreenButton');
const NavMenu = require('./NavMenu');
const styles = require('./styles');
const NavBar = React.memo(({ className, backButton = false, tabs = [], title = '', searchBar = false, navMenu = false }) => {
const NavBar = React.memo(({ className, backButton = false, tabs = [], title = '', searchBar = false, addonsButton = false, fullscreenButton = false, navMenu = false }) => {
const backButtonOnClick = React.useCallback(() => {
window.history.back();
}, []);
@ -14,8 +16,8 @@ const NavBar = React.memo(({ className, backButton = false, tabs = [], title = '
<nav className={classnames(className, styles['nav-bar-container'])}>
{
backButton ?
<NavBarButton
className={styles['nav-bar-button']}
<NavTabButton
className={styles['nav-tab-button']}
icon={'ic_back_ios'}
label={'Back'}
onClick={backButtonOnClick}
@ -26,9 +28,9 @@ const NavBar = React.memo(({ className, backButton = false, tabs = [], title = '
{
Array.isArray(tabs) && tabs.length > 0 ?
tabs.slice(0, 4).map(({ href = '', icon = '', label = '', onClick }) => (
<NavBarButton
<NavTabButton
key={`${href}${icon}${label}`}
className={styles['nav-bar-button']}
className={styles['nav-tab-button']}
href={href}
icon={icon}
label={label}
@ -48,6 +50,18 @@ const NavBar = React.memo(({ className, backButton = false, tabs = [], title = '
:
null
}
{
addonsButton ?
<AddonsButton className={styles['addons-button']} />
:
null
}
{
fullscreenButton ?
<FullscreenButton className={styles['fullscreen-button']} />
:
null
}
{
navMenu ?
<NavMenu className={styles['nav-menu']} />
@ -71,6 +85,8 @@ NavBar.propTypes = {
})),
title: PropTypes.string,
searchBar: PropTypes.bool,
addonsButton: PropTypes.bool,
fullscreenButton: PropTypes.bool,
navMenu: PropTypes.bool
};

View file

@ -1,3 +0,0 @@
const NavBarButton = require('./NavBarButton');
module.exports = NavBarButton;

View file

@ -6,7 +6,7 @@ const Button = require('stremio/common/Button');
const Popup = require('stremio/common/Popup');
const useBinaryState = require('stremio/common/useBinaryState');
const useFullscreen = require('stremio/common/useFullscreen');
const useUser = require('stremio/common/useUser');
const useUser = require('./useUser');
const styles = require('./styles');
const NavMenu = ({ className }) => {

View file

@ -8,7 +8,7 @@ const routesRegexp = require('stremio/common/routesRegexp');
const useLocationHash = require('stremio/common/useLocationHash');
const styles = require('./styles');
const NavBarButton = ({ className, icon = '', label = '', href = '', onClick }) => {
const NavTabButton = ({ className, icon = '', label = '', href = '', onClick }) => {
const locationHash = useLocationHash();
const routeRegexp = React.useMemo(() => {
if (typeof href === 'string' && href.length > 0) {
@ -30,7 +30,7 @@ const NavBarButton = ({ className, icon = '', label = '', href = '', onClick })
return false;
}, [routeRegexp, locationHash]);
return (
<Button className={classnames(className, styles['nav-bar-button-container'], { 'active': active })} title={label} tabIndex={-1} href={href} onClick={onClick}>
<Button className={classnames(className, styles['nav-tab-button-container'], { 'active': active })} title={label} tabIndex={-1} href={href} onClick={onClick}>
{
typeof icon === 'string' && icon.length > 0 ?
<Icon className={styles['icon']} icon={icon} />
@ -47,7 +47,7 @@ const NavBarButton = ({ className, icon = '', label = '', href = '', onClick })
);
};
NavBarButton.propTypes = {
NavTabButton.propTypes = {
className: PropTypes.string,
icon: PropTypes.string,
label: PropTypes.string,
@ -55,4 +55,4 @@ NavBarButton.propTypes = {
onClick: PropTypes.func
};
module.exports = NavBarButton;
module.exports = NavTabButton;

View file

@ -0,0 +1,3 @@
const NavTabButton = require('./NavTabButton');
module.exports = NavTabButton;

View file

@ -1,4 +1,4 @@
.nav-bar-button-container {
.nav-tab-button-container {
display: flex;
flex-direction: row;
align-items: center;

View file

@ -5,7 +5,7 @@
height: 3.2rem;
background-color: var(--color-secondarydark);
.nav-bar-button {
.nav-tab-button {
flex: none;
max-width: 11rem;
height: 3.2rem;
@ -42,7 +42,7 @@
}
}
.nav-menu {
.addons-button, .fullscreen-button, .nav-menu {
flex: none;
width: 3.2rem;
height: 3.2rem;

View file

@ -15,7 +15,6 @@ const useBinaryState = require('./useBinaryState');
const useFullscreen = require('./useFullscreen');
const useLocationHash = require('./useLocationHash');
const useTabIndex = require('./useTabIndex');
const useUser = require('./useUser');
module.exports = {
Button,
@ -34,6 +33,5 @@ module.exports = {
useBinaryState,
useFullscreen,
useLocationHash,
useTabIndex,
useUser
useTabIndex
};

View file

@ -1,25 +1,44 @@
const PathToRegexp = require('path-to-regexp');
const compilePath = (path, options) => {
const keys = [];
const regexp = PathToRegexp(path, keys, { ...options });
return {
regexp,
urlParamsNames: keys.map(({ name }) => name)
};
};
const routesRegexp = {
intro: compilePath('/intro'),
board: compilePath('/'),
discover: compilePath('/discover/:type?/:catalog?'),
library: compilePath('/library/:sort?'),
calendar: compilePath('/calendar'),
search: compilePath('/search'),
detail: compilePath('/detail/:type/:id/:videoId?'),
addons: compilePath('/addons'),
settings: compilePath('/settings'),
player: compilePath('/player')
intro: {
regexp: /^\/intro\/?$/i,
urlParamsNames: []
},
board: {
regexp: /^\/?$/i,
urlParamsNames: []
},
discover: {
regexp: /^\/discover(?:\/([^\/]*?))?(?:\/([^\/]*?))?\/?$/i,
urlParamsNames: ['type', 'catalog']
},
library: {
regexp: /^\/library(?:\/([^\/]*?))?\/?$/i,
urlParamsNames: ['sort']
},
calendar: {
regexp: /^\/calendar\/?$/i,
urlParamsNames: []
},
search: {
regexp: /^\/search\/?$/i,
urlParamsNames: []
},
detail: {
regexp: /^\/detail\/(?:([^\/]+?))\/(?:([^\/]+?))(?:\/([^\/]*?))?\/?$/i,
urlParamsNames: ['type', 'id', 'videoId']
},
addons: {
regexp: /^\/addons\/?$/i,
urlParamsNames: []
},
settings: {
regexp: /^\/settings\/?$/i,
urlParamsNames: []
},
player: {
regexp: /^\/player\/?$/i,
urlParamsNames: []
}
};
module.exports = routesRegexp;

View file

@ -3,12 +3,12 @@ const React = require('react');
const useLocationHash = () => {
const [locationHash, setLocationHash] = React.useState(window.location.hash);
React.useEffect(() => {
const onLocationHashChanged = () => {
const onLocationHashChange = () => {
setLocationHash(window.location.hash);
};
window.addEventListener('hashchange', onLocationHashChanged);
window.addEventListener('hashchange', onLocationHashChange);
return () => {
window.removeEventListener('hashchange', onLocationHashChanged);
window.removeEventListener('hashchange', onLocationHashChange);
};
}, []);
return locationHash;

View file

@ -3,9 +3,9 @@ const PropTypes = require('prop-types');
const ReactIs = require('react-is');
const UrlUtils = require('url');
const { RoutesContainerProvider } = require('../RoutesContainerContext');
const queryParamsForQuery = require('./queryParamsForQuery');
const routeConfigForPath = require('./routeConfigForPath');
const urlParamsForPath = require('./urlParamsForPath');
const queryParamsForQuery = require('../queryParamsForQuery');
const routeConfigForPath = require('../routeConfigForPath');
const urlParamsForPath = require('../urlParamsForPath');
const Route = require('./Route');
const Router = ({ onPathNotMatch, ...props }) => {
@ -29,7 +29,7 @@ const Router = ({ onPathNotMatch, ...props }) => {
}
}, []);
React.useEffect(() => {
const onLocationHashChanged = () => {
const onLocationHashChange = () => {
const { pathname, query } = UrlUtils.parse(window.location.hash.slice(1));
const routeConfig = routeConfigForPath(viewsConfig, pathname);
if (!routeConfig) {
@ -72,10 +72,10 @@ const Router = ({ onPathNotMatch, ...props }) => {
});
});
};
window.addEventListener('hashchange', onLocationHashChanged);
onLocationHashChanged();
window.addEventListener('hashchange', onLocationHashChange);
onLocationHashChange();
return () => {
window.removeEventListener('hashchange', onLocationHashChanged);
window.removeEventListener('hashchange', onLocationHashChange);
};
}, [onPathNotMatch]);
return (

View file

@ -1,161 +1,40 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import VideosList from './VideosList';
import Icon from 'stremio-icons/dom';
import styles from './styles';
const React = require('react');
const { NavBar, MetaPreview } = require('stremio/common');
const VideosList = require('./VideosList');
const StreamsList = require('./StreamsList');
const useMetaItem = require('./useMetaItem');
const useInLibrary = require('./useInLibrary');
require('./styles');
class Detail extends Component {
constructor(props) {
super(props);
this.state = {
logoLoaded: true
};
}
shouldComponentUpdate(nextProps, nextState) {
return nextState.logoLoaded !== this.state.logoLoaded;
}
renderSection({ title, links }) {
return (
<div className={styles['section-container']}>
const Detail = ({ urlParams }) => {
const metaItem = useMetaItem(urlParams.type, urlParams.id, urlParams.videoId);
const [inLibrary, addToLibrary, removeFromLibrary, toggleInLibrary] = useInLibrary(urlParams.id);
return (
<div className={'detail-container'}>
<NavBar className={'nav-bar'} backButton={true} title={metaItem.name} />
<div className={'detail-content'}>
<MetaPreview
{...metaItem}
className={'meta-preview'}
background={null}
inLibrary={inLibrary}
toggleInLibrary={toggleInLibrary}
/>
{
title ?
<div className={styles['title']}>{title}</div>
typeof urlParams.videoId === 'string' && urlParams.videoId.length > 0 ?
<StreamsList
className={'streams-list'}
metaItem={metaItem}
/>
:
null
<VideosList
className={'videos-list'}
metaItem={metaItem}
/>
}
{links.map(link => <a key={link} className={styles['link']}>{link}</a>)}
</div>
);
}
render() {
return (
<div style={this.props.metaItem.background.length > 0 ? { backgroundImage: 'url(' + this.props.metaItem.background + ')' } : { backgroundColor: colors.backgrounddarker }} className={styles['detail-container']}>
<div className={styles['overlay-container']} />
<div className={styles['info-container']}>
{
this.state.logoLoaded ?
<img className={styles['logo']} src={this.props.metaItem.logo} onError={() => this.setState({ logoLoaded: false })} />
:
null
}
<div className={styles['duration']}>{this.props.metaItem.duration}</div>
<div className={styles['release-info']}>
{
this.props.metaItem.releaseInfo.length > 0 ?
this.props.metaItem.releaseInfo
:
this.props.metaItem.released.getFullYear()
}
</div>
<div className={styles['name']}>{this.props.metaItem.name}</div>
<div className={styles['description']}>{this.props.metaItem.description}</div>
{this.renderSection({ title: 'GENRES', links: this.props.metaItem.genres })}
{this.renderSection({ title: 'WRITTEN BY', links: this.props.metaItem.writers })}
{this.renderSection({ title: 'DIRECTED BY', links: this.props.metaItem.directors })}
{this.renderSection({ title: 'CAST', links: this.props.metaItem.cast })}
<div className={styles['action-buttons-container']}>
<a href={this.props.metaItem.links.youtube} className={styles['action-button-container']}>
<Icon className={styles['icon']} icon={'ic_movies'} />
<div className={styles['label']}>Trailer</div>
</a>
<a href={this.props.metaItem.links.imdb} target={'_blank'} className={styles['action-button-container']}>
<Icon className={styles['icon']} icon={'ic_imdb'} />
<div className={styles['label']}>{this.props.metaItem.imdbRating} / 10</div>
</a>
<div className={styles['action-button-container']} onClick={this.props.toggleLibraryButton}>
<Icon className={styles['icon']} icon={this.props.inLibrary ? 'ic_removelib' : 'ic_addlib'} />
<div className={styles['label']}>{this.props.inLibrary ? 'Remove from Library' : 'Add to library'}</div>
</div>
<div className={styles['action-button-container']}>
<Icon className={styles['icon']} icon={'ic_share'} />
<div className={styles['label']}>Share</div>
</div>
</div>
</div>
<VideosList className={styles['videos-list']} videos={this.props.metaItem.videos}></VideosList>
</div>
);
}
}
Detail.propTypes = {
inLibrary: PropTypes.bool.isRequired,
metaItem: PropTypes.object.isRequired,
toggleLibraryButton: PropTypes.func
};
Detail.defaultProps = {
inLibrary: false,
metaItem: {
logo: 'https://images.metahub.space/logo/medium/tt4123430/img',
background: 'https://images.metahub.space/background/medium/tt4123430/img',
duration: '134 min',
releaseInfo: '2018',
released: new Date(2018, 4, 23),
imdbRating: '7.4',
name: 'Fantastic Beasts and Where to Find Them: The Original Screenplay',
description: 'In an effort to thwart Grindelwald' + 's plans ofraisingpurebloodwizardstoansofraisingpurebloodwizardstoansofraisingpurebloodwizardstoansofraising pure-blood wizards toans of raising pure-blood wizards toans of raising pure-blood wizards toans of raising pure-blood wizards toans of raising pure-blood wizards toans of raising pure-blood wizards toans of raising pure-blood wizards toans of raising pure-blood wizards toans of raising pure-blood wizards toans of raising pure-blood wizards toans of raising pure-blood wizards toans of raising pure-blood wizards toans of raising pure-blood wizards toans of raising pure-blood wizards to rule over all non-magical beings, Albus Dumbledore enlists his former student Newt Scamander, who agrees to help, unaware of the dangers that lie ahead. Lines are drawn as love and loyalty are tested, even among the truest friends and family, in an increasingly divided wizarding world.',
genres: ['Adventure', 'Family', 'Fantasy'],
writers: ['J. K. Rowling'],
directors: ['David Yates'],
cast: ['Johny Depp', 'Kevin Guthrie', 'Carmen Ejogo', 'Wolf Roth'],
videos: [
{ id: '1', poster: 'https://www.stremio.com/websiste/home-stremio.png', episode: 1, name: 'The Bing BranHypothesiingBranHypothesiingBranHypothesiingBranHypothesiingBranHypothesiingBran Hypothesiing Bran Hypothesiing Bran Hypothesiing Bran Hypothesiing Bran Hypothesis', description: 'dasdasda', released: new Date(2018, 4, 23), isUpcoming: true, isWatched: true, season: 1 },
{ id: '2', poster: 'https://www.stremio.com/website/home-stremio.png', episode: 2, name: 'The Bing Bran Hypothesis', description: 'dasdasda', released: new Date(2018, 4, 23), isWatched: true, season: 3 },
{ id: '3', episode: 4, name: 'The Luminous Fish Effect', description: 'dasdasda', released: new Date(2018, 4, 23), progress: 50, season: 5 },
{ id: '4', poster: 'https://www.stremiocom/website/home-stremio.png', episode: 5, name: 'The Dumpling Paradox', description: 'dasdasda', released: new Date(2018, 4, 23), progress: 50, season: 4 },
{ id: '5', episode: 8, name: 'The Loobendfeld Decay', description: 'dasdasda', released: new Date(2018, 4, 23), isUpcoming: true, season: 5 },
{ id: '6', poster: 'https://www.stremio.com/website/home-stremio.png', episode: 1, name: 'The Bing BranHypothesiingBranHypothesiingBranHypothesiingBranHypothesiingBranHypothesiingBran Hypothesiing Bran Hypothesiing Bran Hypothesiing Bran Hypothesiing Bran Hypothesis', description: 'dasdasda', released: new Date(2018, 4, 23), isUpcoming: true, isWatched: true, season: 1 },
{ id: '7', poster: 'https://www.stremio.com/website/home-stremio.png', episode: 2, name: 'The Bing Bran Hypothesis', description: 'dasdasda', released: new Date(2018, 4, 23), isWatched: true, season: 1 },
{ id: '8', episode: 4, name: 'The Luminous Fish Effect', description: 'dasdasda', released: new Date(2018, 4, 23), progress: 50, season: 3 },
{ id: '9', poster: 'https://www.stremiocom/website/home-stremio.png', episode: 5, name: 'The Dumpling Paradox', description: 'dasdasda', released: new Date(2018, 4, 23), progress: 50, season: 2 },
{ id: '10', episode: 8, name: 'The Loobendfeld Decay', description: 'dasdasda', released: new Date(2018, 4, 23), isUpcoming: true, season: 5 },
{ id: '11', episode: 8, name: 'The Loobendfeld Decay', description: 'dasdasda', released: new Date(2018, 4, 23), isUpcoming: true, season: 1 },
{ id: '12', poster: 'https://www.stremio.com/website/home-stremio.png', episode: 1, name: 'The Bing BranHypothesiingBranHypothesiingBranHypothesiingBranHypothesiingBranHypothesiingBran Hypothesiing Bran Hypothesiing Bran Hypothesiing Bran Hypothesiing Bran Hypothesis', description: 'dasdasda', released: new Date(2018, 4, 23), isUpcoming: true, isWatched: true, season: 1 },
{ id: '13', poster: 'https://www.stremio.com/website/home-stremio.png', episode: 2, name: 'The Bing Bran Hypothesis', description: 'dasdasda', released: new Date(2018, 4, 23), isWatched: true, season: 1 },
{ id: '14', episode: 4, name: 'The Luminous Fish Effect', description: 'dasdasda', released: new Date(2018, 4, 23), progress: 50, season: 3 },
{ id: '15', poster: 'https://www.stremiocom/website/home-stremio.png', episode: 5, name: 'The Dumpling Paradox', description: 'dasdasda', released: new Date(2018, 4, 23), progress: 50, season: 2 },
{ id: '16', episode: 8, name: 'The Loobendfeld Decay', description: 'dasdasda', released: new Date(2018, 4, 23), isUpcoming: true, season: 5 },
{ id: '17', episode: 8, name: 'The Loobendfeld Decay', description: 'dasdasda', released: new Date(2018, 4, 23), isUpcoming: true, season: 1 },
{ id: '18', poster: 'https://www.stremio.com/website/home-stremio.png', episode: 1, name: 'The Bing BranHypothesiingBranHypothesiingBranHypothesiingBranHypothesiingBranHypothesiingBran Hypothesiing Bran Hypothesiing Bran Hypothesiing Bran Hypothesiing Bran Hypothesis', description: 'dasdasda', released: new Date(2018, 4, 23), isUpcoming: true, isWatched: true, season: 1 },
{ id: '19', poster: 'https://www.stremio.com/website/home-stremio.png', episode: 2, name: 'The Bing Bran Hypothesis', description: 'dasdasda', released: new Date(2018, 4, 23), isWatched: true, season: 1 },
{ id: '20', episode: 4, name: 'The Luminous Fish Effect', description: 'dasdasda', released: new Date(2018, 4, 23), progress: 50, season: 3 },
{ id: '21', poster: 'https://www.stremiocom/wsebsite/home-stremio.png', episode: 5, name: 'The Dumpling Paradox', description: 'dasdasda', released: new Date(2018, 4, 23), progress: 50, season: 2 },
{ id: '22', episode: 8, name: 'The Loobendfeld Decay', description: 'dasdasda', released: new Date(2018, 4, 23), isUpcoming: true, season: 5 },
{ id: '23', episode: 8, name: 'The Loobendfeld Decay', description: 'dasdasda', released: new Date(2018, 4, 23), isUpcoming: true, season: 1 },
{ id: '24', poster: 'https://www.stremio.com/website/home-stremio.png', episode: 1, name: 'The Bing BranHypothesiingBranHypothesiingBranHypothesiingBranHypothesiingBranHypothesiingBran Hypothesiing Bran Hypothesiing Bran Hypothesiing Bran Hypothesiing Bran Hypothesis', description: 'dasdasda', released: new Date(2018, 4, 23), isUpcoming: true, isWatched: true, season: 1 },
{ id: '25', poster: 'https://www.stremio.com/website/home-stremio.png', episode: 2, name: 'The Bing Bran Hypothesis', description: 'dasdasda', released: new Date(2018, 4, 23), isWatched: true, season: 1 },
{ id: '26', episode: 4, name: 'The Luminous Fish Effect', description: 'dasdasda', released: new Date(2018, 4, 23), progress: 50, season: 3 },
{ id: '27', poster: 'https://www.stremiocom/website/home-stremio.png', episode: 5, name: 'The Dumpling Paradox', description: 'dasdasda', released: new Date(2018, 4, 23), progress: 50, season: 2 },
{ id: '28', episode: 8, name: 'The Loobendfeld Decay', description: 'dasdasda', released: new Date(2018, 4, 23), isUpcoming: true, season: 5 },
{ id: '29', episode: 8, name: 'The Loobendfeld Decay', description: 'dasdasda', released: new Date(2018, 4, 23), isUpcoming: true, season: 1 },
{ id: '30', poster: 'https://www.stremio.com/website/home-stremio.png', episode: 1, name: 'The Bing BranHypothesiingBranHypothesiingBranHypothesiingBranHypothesiingBranHypothesiingBran Hypothesiing Bran Hypothesiing Bran Hypothesiing Bran Hypothesiing Bran Hypothesis', description: 'dasdasda', released: new Date(2018, 4, 23), isUpcoming: true, isWatched: true, season: 1 },
{ id: '31', poster: 'https://www.stremio.com/website/home-stremio.png', episode: 2, name: 'The Bing Bran Hypothesis', description: 'dasdasda', released: new Date(2018, 4, 23), isWatched: true, season: 1 },
{ id: '32', episode: 4, name: 'The Luminous Fish Effect', description: 'dasdasda', released: new Date(2018, 4, 23), progress: 50, season: 1 },
{ id: '33', poster: 'https://www.stremiocom/website/home-stremio.png', episode: 5, name: 'The Dumpling Paradox', description: 'dasdasda', released: new Date(2018, 4, 23), progress: 50, season: 2 },
{ id: '34', episode: 8, name: 'The Loobendfeld Decay', description: 'dasdasda', released: new Date(2018, 4, 23), isUpcoming: true, season: 1 },
{ id: '35', episode: 8, name: 'The Loobendfeld Decay', description: 'dasdasda', released: new Date(2018, 4, 23), isUpcoming: true, season: 1 },
{ id: '36', poster: 'https://www.stremio.com/website/home-stremio.png', episode: 1, name: 'The Bing BranHypothesiingBranHypothesiingBranHypothesiingBranHypothesiingBranHypothesiingBran Hypothesiing Bran Hypothesiing Bran Hypothesiing Bran Hypothesiing Bran Hypothesis', description: 'dasdasda', released: new Date(2018, 4, 23), isUpcoming: true, isWatched: true, season: 1 },
{ id: '37', poster: 'https://www.stremio.com/website/home-stremio.png', episode: 2, name: 'The Bing Bran Hypothesis', description: 'dasdasda', released: new Date(2018, 4, 23), isWatched: true, season: 1 },
{ id: '38', episode: 4, name: 'The Luminous Fish Effect', description: 'dasdasda', released: new Date(2018, 4, 23), progress: 50, season: 1 },
{ id: '39', poster: 'https://www.stremiocom/website/home-stremio.png', episode: 5, name: 'The Dumpling Paradox', description: 'dasdasda', released: new Date(2018, 4, 23), progress: 50, season: 2 },
{ id: '40', episode: 8, name: 'The Loobendfeld Decay', description: 'dasdasda', released: new Date(2018, 4, 23), isUpcoming: true, season: 1 },
{ id: '41', episode: 8, name: 'The Loobendfeld Decay', description: 'dasdasda', released: new Date(2018, 4, 23), isUpcoming: true, season: 1 },
{ id: '42', poster: 'https://www.stremio.com/website/home-stremio.png', episode: 1, name: 'The Bing BranHypothesiingBranHypothesiingBranHypothesiingBranHypothesiingBranHypothesiingBran Hypothesiing Bran Hypothesiing Bran Hypothesiing Bran Hypothesiing Bran Hypothesis', description: 'dasdasda', released: new Date(2018, 4, 23), isUpcoming: true, isWatched: true, season: 1 },
{ id: '43', poster: 'https://www.stremio.com/website/home-stremio.png', episode: 2, name: 'The Bing Bran Hypothesis', description: 'dasdasda', released: new Date(2018, 4, 23), isWatched: true, season: 1 },
{ id: '44', episode: 4, name: 'The Luminous Fish Effect', description: 'dasdasda', released: new Date(2018, 4, 23), progress: 50, season: 1 },
{ id: '45', poster: 'https://www.stremiocom/website/home-stremio.png', episode: 5, name: 'The Dumpling Paradox', description: 'dasdasda', released: new Date(2018, 4, 23), progress: 50, season: 2 },
{ id: '46', episode: 8, name: 'The Loobendfeld Decay', description: 'dasdasda', released: new Date(2018, 4, 23), isUpcoming: true, season: 1 }
],
links: {
share: '',
imdb: 'https://www.imdb.com/title/tt4123430/?ref_=fn_al_tt_3',
youtube: '#/player'
}
}
</div>
);
};
export default Detail;
module.exports = Detail;

View file

@ -1,3 +1,3 @@
import Detail from './Detail';
const Detail = require('./Detail');
export default Detail;
module.exports = Detail;

View file

@ -1,175 +1,31 @@
.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;
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
background-color: var(--color-background);
.overlay-container {
position: absolute;
z-index: 0;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: var(--color-backgrounddarker60);
.nav-bar {
flex: none;
align-self: stretch;
}
.info-container {
position: absolute;
z-index: 1;
top: 0;
left: 0;
right: 40%;
bottom: 0;
padding: calc(var(--spacing) * 3);
.detail-content {
flex: 1;
align-self: stretch;
display: flex;
flex-direction: row;
.logo {
display: block;
height: calc(var(--action-button-width) * 1.2);
object-fit: contain;
.meta-preview {
flex: 1;
align-self: stretch;
}
.logo-error {
display: none;
.videos-list, .streams-list {
flex-grow: 0;
flex-shrink: 0;
flex-basis: 30rem;
align-self: stretch;
}
.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;
}
}

View file

@ -0,0 +1,8 @@
const { useBinaryState } = require('stremio/common');
const useInLibrary = (id = '') => {
const [inLibrary, addToLibrary, removeFromLibrary, toggleInLibrary] = useBinaryState(false);
return [inLibrary, addToLibrary, removeFromLibrary, toggleInLibrary];
};
module.exports = useInLibrary;

View file

@ -0,0 +1,39 @@
const React = require('react');
const useMetaItem = (type = '', id = '', videoId = '') => {
const [metaItem] = React.useState(() => ({
id,
type,
name: 'Underworld',
logo: 'https://images.metahub.space/logo/medium/tt0320691/img',
background: 'https://images.metahub.space/background/medium/tt0320691/img',
duration: '121 min',
releaseInfo: '2003',
released: '2003-09-19T00:00:00.000Z',
description: 'Selene, a vampire warrior, is entrenched in a conflict between vampires and werewolves, while falling in love with Michael, a human who is sought by werewolves for unknown reasons.',
genres: ['Action', 'Fantasy', 'Thriller'],
writers: ['Kevin Grevioux', 'Len Wiseman', 'Danny McBride', 'Danny McBride'],
directors: ['Len Wiseman'],
cast: ['Kate Beckinsale', 'Scott Speedman', 'Michael Sheen', 'Shane Brolly'],
imdbRating: '7.0',
links: {
trailer: 'mn4O3iQ8B_s',
imdb: 'tt0320691',
share: 'movie/underworld-0320691'
},
videos: [
{
id: '1',
name: 'How to create a Stremio add-on with Node.js',
description: 'This is a step-by-step tutorial on how to create your own add-on using Node.js.',
released: 'Mon Jul 01 2019 00:00:00 GMT+0300 (Eastern European Summer Time)',
poster: 'https://theme.zdassets.com/theme_assets/2160011/77a6ad5aee11a07eb9b87281070f1aadf946f2b3.png',
season: 0,
episode: 0
}
]
}));
return metaItem;
};
module.exports = useMetaItem;