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

This commit is contained in:
NikolaBorislavovHristov 2019-01-17 11:35:27 +02:00
commit 15ca1fb614
14 changed files with 861 additions and 138 deletions

View file

@ -1,4 +1,4 @@
import { Calendar, Discover, Addons, Settings, Board, Player } from 'stremio-routes';
import { Calendar, Discover, Addons, Settings, Board, Player, Detail } from 'stremio-routes';
const config = {
views: [
@ -27,6 +27,10 @@ const config = {
{
path: '/settings',
component: Settings
},
{
path: '/detail',
component: Detail
}
]
},

View file

@ -6,7 +6,6 @@ import MetadataItem from './MetadataItem';
import Router from './Router';
import LibraryItemList from './LibraryItemList';
import MetaItem from './MetaItem';
import Addon from './Addon';
import ShareAddon from './ShareAddon';
import UserPanel from './UserPanel';
import Slider from './Slider';
@ -20,7 +19,6 @@ export {
Router,
LibraryItemList,
MetaItem,
Addon,
ShareAddon,
UserPanel,
Slider

View file

@ -32,12 +32,26 @@ const renderType = (types) => {
}
return (
<div className={styles['type']}>
{types.length <= 1 ? types.join('') : types.slice(0, -1).join(', ') + ' & ' + types[types.length - 1]}
<div className={styles['types-container']}>
<div className={styles['type']}>
{types.length <= 1 ? types.join('') : types.slice(0, -1).join(', ') + ' & ' + types[types.length - 1]}
</div>
</div>
);
}
const renderHostname = (hostname) => {
if (hostname.length === 0) {
return null;
}
return (
<div className={styles['hostname-container']}>
<div className={styles['hostname']}>{hostname}</div>
</div>
)
}
const renderDescription = (description) => {
if (description.length === 0) {
return null;
@ -48,25 +62,9 @@ const renderDescription = (description) => {
);
}
const renderUrls = (urls) => {
if (urls.length === 0) {
return null;
}
return (
<div className={styles['urls-container']}>
{urls.map((url) => {
return (
<div key={url} className={styles['url']}>{url}</div>
);
})}
</div>
);
}
const Addon = (props) => {
return (
<div className={styles['addon']}>
<div className={classnames(styles['addon'], props.className)}>
<div className={styles['logo-container']}>
<Icon className={styles['logo']} icon={props.logo.length === 0 ? 'ic_addons' : props.logo} />
</div>
@ -77,28 +75,30 @@ const Addon = (props) => {
</div>
</div>
{renderType(props.types)}
{renderHostname(props.hostname)}
{renderDescription(props.description)}
{renderUrls(props.urls)}
<div className={styles['buttons']}>
<div className={classnames(styles['button'], props.isInstalled ? styles['uninstall-button'] : styles['install-button'])} onClick={props.onToggleClicked}>
<span className={styles['label']}>{props.isInstalled ? 'Uninstall' : 'Install'}</span>
</div>
<div className={classnames(styles['button'], styles['share-button'])} onClick={props.shareAddon}>
<Icon className={styles['icon']} icon={'ic_share'} />
<span className={styles['label']}>SHARE ADD-ON</span>
</div>
<div className={classnames(styles['button'], props.isInstalled ? styles['install-button'] : styles['uninstall-button'])} onClick={props.onToggleClicked}>
<span className={styles['label']}>{props.isInstalled ? 'Install' : 'Uninstall'}</span>
</div>
</div>
</div>
);
}
Addon.propTypes = {
className: PropTypes.string,
logo: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
version: PropTypes.string.isRequired,
types: PropTypes.arrayOf(PropTypes.string).isRequired,
hostname: PropTypes.string.isRequired,
description: PropTypes.string.isRequired,
urls: PropTypes.arrayOf(PropTypes.string).isRequired,
isOfficial: PropTypes.bool.isRequired,
isInstalled: PropTypes.bool.isRequired,
shareAddon: PropTypes.func.isRequired,
onToggleClicked: PropTypes.func.isRequired
@ -108,9 +108,10 @@ Addon.defaultProps = {
name: '',
version: '',
types: [],
hostname: '',
description: '',
urls: [],
isOfficial: false,
isInstalled: false
};
export default Addon;
export default Addon;

View file

@ -1,34 +1,22 @@
.addon {
--addon-width: 514px;
--name-font-size: 20px;
--version-font-size: 12px;
--type-font-size: 12px;
--description-font-size: 12px;
--url-font-size: 12px;
--button-border-width: 2px;
--button-label-font-size: 14px;
}
.addon {
display: grid;
display: inline-grid;
width: var(--addon-width);
padding: 2%;
background-color: var(--color-background);
grid-template-columns: 1fr 4fr;
grid-template-rows: calc(0.04 * var(--addon-width)) calc(0.04 * var(--addon-width)) auto auto calc((0.08 * var(--addon-width)));
padding: 1.6em;
background-color: var(--color-backgroundlighter);
grid-template-columns: 1fr 5fr 4fr;
grid-template-rows: calc(0.03 * var(--addon-width)) calc(0.03 * var(--addon-width)) calc(0.03 * var(--addon-width)) auto;
grid-template-areas:
"logo header"
"logo type"
"logo description"
"urls urls"
"buttons buttons";
"logo header buttons"
"logo type buttons"
"logo hostname buttons"
"logo description buttons";
.logo-container {
grid-area: logo;
.logo {
width: calc(0.2 * var(--addon-width));
height: calc(0.2 * var(--addon-width));
width: calc(0.12 * var(--addon-width));
height: calc(0.12 * var(--addon-width));
padding: 20%;
fill: var(--color-surfacelighter);
background-color: var(--color-backgrounddarker);
@ -50,7 +38,7 @@
.name {
max-width: 80%;
margin-right: 3%;
font-size: var(--name-font-size);
font-size: 1.8em;
color: var(--color-surfacelighter);
overflow: hidden;
white-space: pre;
@ -59,7 +47,6 @@
.version {
flex: 1;
font-size: var(--version-font-size);
color: var(--color-surface);
overflow: hidden;
white-space: pre;
@ -68,44 +55,56 @@
}
}
.type {
.types-container {
grid-area: type;
display: flex;
align-items: center;
padding-left: 4%;
font-size: var(--type-font-size);
overflow: hidden;
color: var(--color-secondarylighter);
.type {
overflow: hidden;
white-space: pre;
text-overflow: ellipsis;
}
}
.hostname-container {
grid-area: hostname;
display: flex;
align-items: center;
padding-left: 4%;
overflow: hidden;
overflow-wrap: break-word;
color: var(--color-surfacelighter);
.hostname {
overflow: hidden;
white-space: pre;
text-overflow: ellipsis;
}
}
.description {
grid-area: description;
padding-left: 4%;
font-size: var(--description-font-size);
color: var(--color-surfacelighter);
word-break: break-all; //Firefox doesn't support { break-word }
word-break: break-word;
}
.urls-container {
grid-area: urls;
padding: 4% 0%;
overflow: auto;
word-break: break-all;
.url {
font-size: var(--url-font-size);
color: var(--color-surface);
}
overflow: hidden;
overflow-wrap: break-word;
}
.buttons {
grid-area: buttons;
height: calc(0.12 * var(--addon-width));
display: flex;
align-items: stretch;
flex-direction: column;
align-items: flex-end;
justify-content: space-between;
.button {
width: 46%;
width: 65%;
height: calc(0.05 * var(--addon-width));
cursor: pointer;
display: flex;
align-items: center;
@ -114,11 +113,12 @@
border-style: solid;
.icon {
width: 7%;
margin-right: 2%;
width: 8%;
margin-right: 3%;
}
.label {
font-size: 1.1em;
color: var(--color-surfacelighter);
}
@ -134,7 +134,8 @@
}
&:hover {
background-color: var(--color-secondarylighter);
border-color: var(--color-secondarylight);
background-color: var(--color-secondarylight);
.icon {
fill: var(--color-surfacelighter);
@ -151,15 +152,23 @@
background-color: var(--color-signal5);
&:hover {
background-color: var(--color-signal580);
background-color: var(--color-signal560);
}
}
&.uninstall-button {
border-color: var(--color-surfacedark);
.label {
color: var(--color-surfacedark);
}
&:hover {
background-color: var(--color-surfacedark);
.label {
color: var(--color-surfacelighter);
}
}
}

View file

@ -1,11 +1,154 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import Addon from './Addon';
import Icon from 'stremio-icons/dom';
import styles from './styles';
const ADDON_CATEGORIES = {
OFFICIAL: 1,
COMMUNITY: 2,
MY: 3
};
const ADDON_TYPES = {
All: -1,
Movies: 0,
Series: 1,
Channels: 2,
Others: 3
};
const DEFAULT_TYPE = 'All';
class Addons extends Component {
constructor(props) {
super(props);
this.state = {
selectedCategory: ADDON_CATEGORIES.OFFICIAL,
selectedAddonType: DEFAULT_TYPE
};
}
changeSelectedCategory = (event) => {
event.currentTarget.blur();
this.setState({ selectedCategory: ADDON_CATEGORIES[event.currentTarget.dataset.category] });
}
changeSelectedAddonType = (event) => {
event.currentTarget.blur();
this.setState({ selectedAddonType: event.currentTarget.dataset.type })
}
shouldComponentUpdate(nextProps, nextState) {
return nextState.selectedCategory !== this.state.selectedCategory ||
nextState.selectedAddonType !== this.state.selectedAddonType;
}
componentDidUpdate(prevProps, prevState) {
if (this.state.selectedCategory !== prevState.selectedCategory || !this.getAddonTypes().includes(this.state.selectedAddonType)) {
this.setState({ selectedAddonType: DEFAULT_TYPE })
}
}
getAddonTypes() {
const addonTypes = this.props.addons
.filter((addon) => {
if (this.state.selectedCategory === ADDON_CATEGORIES.OFFICIAL) return addon.isOfficial === true;
if (this.state.selectedCategory === ADDON_CATEGORIES.COMMUNITY) return addon.isOfficial === false;
if (this.state.selectedCategory === ADDON_CATEGORIES.MY) return addon.isInstalled === true;
})
.map((addon) => addon.types)
.join()
.split(',')
.filter((type, index, types) => types.indexOf(type) === index)
.sort(function(a, b) {
const valueA = ADDON_TYPES[a];
const valueB = ADDON_TYPES[b];
if (!isNaN(valueA) && !isNaN(valueB)) return valueA - valueB;
if (!isNaN(valueA)) return -1;
if (!isNaN(valueB)) return 1;
return a - b;
});
return addonTypes;
}
render() {
return (
<div style={{ color: 'pink', paddingTop: 40 }}>You're on the Addons Tab</div>
<div className={styles['addons-container']}>
<div className={styles['side-menu']}>
<div className={styles['add-addon-container']}>
<Icon className={styles['add-addon-icon']} icon={'ic_plus'} />
<div className={styles['add-addon-label']}>Add new Add-On</div>
</div>
{Object.keys(ADDON_CATEGORIES).map((category) =>
<div className={classnames(styles['label'], { [styles['selected']]: this.state.selectedCategory === ADDON_CATEGORIES[category] })} tabIndex={'0'} key={category} data-category={category} onClick={this.changeSelectedCategory}>
{category}
</div>
)}
<div className={classnames(styles['label'], { [styles['selected']]: this.state.selectedAddonType === DEFAULT_TYPE })} tabIndex={'0'} data-type={DEFAULT_TYPE} onClick={this.changeSelectedAddonType}>
All
</div>
{this.getAddonTypes().map((type) =>
<div className={classnames(styles['label'], { [styles['selected']]: this.state.selectedAddonType === type })} tabIndex={'0'} key={type} data-type={type} onClick={this.changeSelectedAddonType}>
{type}
</div>
)}
</div>
<div className={styles['scroll-container']}>
{this.props.addons
.filter((addon) => {
if (this.state.selectedCategory === ADDON_CATEGORIES.OFFICIAL) return addon.isOfficial === true;
if (this.state.selectedCategory === ADDON_CATEGORIES.COMMUNITY) return addon.isOfficial === false;
if (this.state.selectedCategory === ADDON_CATEGORIES.MY) return addon.isInstalled === true;
})
.filter((addon) => {
return this.state.selectedAddonType === DEFAULT_TYPE ||
addon.types.indexOf(this.state.selectedAddonType) !== -1;
})
.map((addon) =>
<Addon key={addon.name}
className={styles['addon']}
logo={addon.logo}
name={addon.name}
version={addon.version}
isOfficial={addon.isOfficial}
isInstalled={addon.isInstalled}
types={addon.types}
hostname={addon.hostname}
description={addon.description}
/>
)}
</div>
</div>
);
}
}
Addons.propTypes = {
addons: PropTypes.arrayOf(PropTypes.object).isRequired
};
Addons.defaultProps = {
addons: [
{ logo: 'ic_series', name: 'Watch Hub', version: '1.3.0', isOfficial: true, isInstalled: false, types: ['ovies', 'Series'], hostname: 'piratebay-stremio-addon.herokuappstremio-addon.herokuappstremio-addon.herokuappstremio-addon.herokuappstremio-addon.herokuappstremio-addon.herokuappstremio-addon.herokuappstremio-addon.herokuapp.com', description: 'Find where to stream your favourite movies and shows amongst iTunes, Hulu, Amazon and other UK/US services.' },
{ name: 'Cinemeta', version: '2.4.0', isOfficial: false, isInstalled: true, types: ['Moies', 'Series'], hostname: 'stremio-zooqle.now.sh', description: 'Watch your favourite YouTube channels ad-free and get notified when they upload new videos.' },
{ logo: 'ic_youtube_small', name: 'YouTube', version: '1.3.0', isOfficial: false, isInstalled: true, types: ['Channels', 'Videos'], hostname: 'pct.best4stremio.space', 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.' },
{ name: 'OpenSubtitles', version: '1.3.0', isOfficial: false, isInstalled: false, types: ['Movie', 'Seies'], description: 'Watch your favourite YouTube channels ad-free and get notified when they upload new videos.' },
{ logo: 'ic_series', name: 'Zooqle', version: '1.3.0', isOfficial: true, isInstalled: false, types: ['Movies', 'Series'], hostname: 'pct.best4stremio.space', description: 'Find where to stream your favourite movies and shows amongst iTunes, Hulu, Amazon and other UK/US services.' },
{ name: 'PirateBay Addon', version: '2.4.0', isOfficial: false, isInstalled: true, types: ['Movies', 'eries'], hostname: 'pct.best4stremio.space', description: 'Watch your favourite YouTube channels ad-free and get notified when they upload new videos.' },
{ logo: 'ic_youtube_small', name: 'Popcorn Time', version: '1.3.0', isOfficial: false, isInstalled: true, types: ['Channels', 'Videos'], hostname: 'pct.best4stremio.space', 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.' },
{ name: 'IBERIAN', version: '1.3.0', isOfficial: false, isInstalled: true, types: ['Movies', 'Other'], hostname: 'pct.best4stremio.space', description: 'Watch your favourite YouTube channels ad-free and get notified when they upload new videos.' },
{ logo: 'ic_series', name: 'Ex Addon', version: '1.3.0', isOfficial: false, isInstalled: false, types: ['Movies', 'Series'], hostname: 'pct.best4stremio.space', description: 'Find where to stream your favourite movies and shows amongst iTunes, Hulu, Amazon and other UK/US services.' },
{ name: 'Juan Carlos', version: '2.4.0', isOfficial: false, isInstalled: true, types: ['Movies', 'Seris', 'Channels'], hostname: 'pct.best4stremio.space', description: 'Watch your favourite YouTube channels ad-free and get notified when they upload new videos.' },
{ logo: 'ic_youtube_small', name: 'Juan Carlos Torrents', version: '1.3.0', isOfficial: false, isInstalled: true, types: ['Channels', 'Videos'], hostname: 'pct.best4stremio.space', 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.' },
{ name: 'Juan Carlos 2', version: '1.3.0', isOfficial: false, isInstalled: false, types: ['Moes', 'Serie'], hostname: 'pct.best4stremio.space', description: 'Watch your favourite YouTube channels ad-free and get notified when they upload new videos.' },
{ logo: 'ic_series', name: 'Netflix', version: '1.3.0', isOfficial: true, isInstalled: false, types: ['Movies', 'Series'], hostname: 'pct.best4stremio.space', description: 'Find where to stream your favourite movies and shows amongst iTunes, Hulu, Amazon and other UK/US services.' },
{ name: 'Anime Addon', version: '2.4.0', isOfficial: false, isInstalled: true, types: ['Movies', 'Series'], hostname: 'pct.best4stremio.space', description: 'Watch your favourite YouTube channels ad-free and get notified when they upload new videos.' },
{ logo: 'ic_youtube_small', name: 'DTube', version: '1.3.0', isOfficial: true, isInstalled: true, types: ['hannels', 'Videos'], hostname: 'pct.best4stremio.space', 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.' },
{ name: 'Mixer', version: '1.3.0', isOfficial: false, isInstalled: true, types: ['Movies', 'Series'], hostname: 'pct.best4stremio.space', description: 'Watch your favourite YouTube channels ad-free and get notified when they upload new videos.' }
]
};
export default Addons;

View file

@ -0,0 +1,108 @@
.addons-container {
--addon-width: 960px;
--label-width: 196px;
--label-height: 44px;
--spacing: 8px;
--button-border-width: 2px;
font-size: 14px;
}
.addons-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: row;
.side-menu {
width: calc(var(--label-width) + var(--spacing) * 5.5);
display: flex;
flex-direction: column;
padding: 0 calc(var(--spacing) * 2.5 + var(--button-border-width));
margin: calc(var(--spacing) * 2.5 + var(--button-border-width)) calc(var(--spacing) * 4.5) calc(var(--spacing) * 2.5 + var(--button-border-width)) 0;
overflow-y: auto;
overflow-x: hidden;
.add-addon-container {
width: var(--label-width);
min-height: var(--label-height);
display: flex;
align-items: center;
cursor: pointer;
margin-top: var(--button-border-width);
margin-bottom: calc(var(--spacing) * 2.5 + var(--button-border-width));
padding: calc(var(--spacing) * 1.5);
background: var(--color-signal5);
.add-addon-icon {
flex: 1;
margin-right: calc(var(--spacing) * 2);
fill: var(--color-surfacelighter);
}
.add-addon-label {
flex: 8;
font-size: 1.2em;
color: var(--color-surfacelighter);
overflow: hidden;
white-space: pre;
text-overflow: ellipsis;
}
&:hover {
background: var(--color-signal560);
}
}
.label {
width: var(--label-width);
min-height: var(--label-height);
cursor: pointer;
margin-top: var(--button-border-width);
padding: calc(var(--spacing) * 1.5);
font-size: 1.2em;
overflow: hidden;
white-space: pre;
text-overflow: ellipsis;
color: var(--color-surfacelight);
&.selected {
color: var(--color-surfacelighter);
background: var(--color-primarydark);
&:hover {
background: var(--color-primarydark);
}
}
&:focus {
outline: var(--button-border-width) solid var(--color-surfacelighter);
}
&:hover {
color: var(--color-surfacelighter);
background: var(--color-backgroundlighter);
outline: none;
}
&:nth-child(4) {
margin-bottom: calc(var(--spacing) * 2.5 + var(--button-border-width));
}
&:last-child {
margin-bottom: var(--button-border-width);
}
}
}
.scroll-container {
flex: 1;
align-self: stretch;
margin: calc(var(--spacing) * 2.5 + var(--button-border-width)) calc(var(--spacing) * 2.5 + var(--button-border-width)) calc(var(--spacing) * 2.5 + var(--button-border-width)) 0;
overflow-y: auto;
overflow-x: hidden;
>:not(:first-child) {
margin-top: calc(var(--spacing) * 2.5 + var(--button-border-width));
}
}
}

View file

@ -1,9 +1,161 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import VideosList from './VideosList';
import Icon from 'stremio-icons/dom';
import styles from './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']}>
{
title ?
<div className={styles['title']}>{title}</div>
:
null
}
{links.map(link => <a key={link} className={styles['link']}>{link}</a>)}
</div>
);
}
render() {
return null;
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'
}
}
};
export default Detail;

View file

@ -87,7 +87,7 @@ const renderProgress = (progress) => {
const Video = (props) => {
return (
<div onClick={props.onVideoClicked} className={classnames(styles['video-container'], props.className)}>
<div className={classnames(styles['video-container'], props.className)} data-video-id={props.id} onClick={props.onClick}>
<div className={styles['flex-row-container']}>
{renderPoster(props.poster)}
<div className={styles['info-container']}>
@ -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: '',

View file

@ -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);
}
}
}
}

View file

@ -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 (
<div className={styles['videos-list-container']}>
<div className={classnames(styles['videos-list-container'], this.props.className)}>
<div className={styles['seasons-bar']}>
<div className={styles['button-container']} onClick={this.onPrevButtonClicked}>
<Icon className={styles['button-icon']} icon={'ic_arrow_left'} />
</div>
<select value={this.state.selectedSeason} onChange={this.changeSeason}>
{this.seasons.map((season) =>
<option key={season} value={season}>
{season}
</option>
)}
</select>
<Popup ref={this.seasonsPopupRef} className={'detail-popup-container'} onOpen={this.onSeasonsPopupOpen} onClose={this.onSeasonsPopupClose}>
<Popup.Label>
<div className={classnames(styles['season-bar-button'], { 'active': this.state.seasonsPopupOpen })}>
<div className={styles['season-label']}>Season</div>
<div className={styles['season-number']}>{this.state.selectedSeason}</div>
<Icon className={styles['icon']} icon={'ic_arrow_down'} />
</div>
</Popup.Label>
<Popup.Menu>
<div className={styles['popup-content']}>
{this.seasons.map((season) =>
<div className={classnames(styles['season'], { [styles['selected-season']]: this.state.selectedSeason === season })} key={season} data-season={season} onClick={this.changeSeason}>
<div className={styles['season-label']}>Season</div>
<div className={styles['season-number']}>{season}</div>
</div>
)}
</div>
</Popup.Menu>
</Popup>
<div className={styles['button-container']} onClick={this.onNextButtonClicked} >
<Icon className={styles['button-icon']} icon={'ic_arrow_left'} />
</div>
@ -58,13 +90,16 @@ class VideosList extends Component {
.map((video) =>
<Video key={video.id}
className={styles['video']}
id={video.id}
poster={video.poster}
episode={video.episode}
season={video.season}
title={video.name}
released={video.released}
isWatched={video.isWatched}
isUpcoming={video.isUpcoming}
progress={video.progress}
onClick={this.onClick}
/>
)}
</div>
@ -74,6 +109,7 @@ class VideosList extends Component {
}
VideosList.propTypes = {
className: PropTypes.string,
videos: PropTypes.arrayOf(PropTypes.object).isRequired
};
VideosList.defaultProps = {

View file

@ -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);
}
}
}
}

View file

@ -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;
}
}

View file

@ -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']}
/>
</div>
))
@ -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']}
/>
</div>
))
@ -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']}
/>
</div>
))
@ -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']}
/>
</div>
));