diff --git a/src/routes/Discover/Discover.js b/src/routes/Discover/Discover.js
index 620dac978..2e1df1274 100644
--- a/src/routes/Discover/Discover.js
+++ b/src/routes/Discover/Discover.js
@@ -1,134 +1,43 @@
const React = require('react');
-const classnames = require('classnames');
-const { Input } = require('stremio-navigation');
-const Icon = require('stremio-icons/dom');
-const { MainNavBar, MetaItem, MetaPreview, Popup, useBinaryState } = require('stremio-common');
+const { MainNavBar, MetaItem, MetaPreview } = require('stremio-common');
+const PickerMenu = require('./PickerMenu');
const useCatalog = require('./useCatalog');
const styles = require('./styles');
// TODO impl refocus to left of the scroll view
-const Discover = ({ urlParams }) => {
- const catalog = useCatalog(urlParams);
- const [typePickerOpen, typePickerOnOpen, typePickerOnClose] = useBinaryState(false);
- const [catalogPickerOpen, catalogPickerOnOpen, catalogPickerOnClose] = useBinaryState(false);
- const [categoryPickerOpen, categoryPickerOnOpen, categoryPickerOnClose] = useBinaryState(false);
- React.useEffect(() => {
- if (typeof urlParams.type !== 'string' || typeof urlParams.catalog !== 'string') {
- const type = urlParams.type || 'movie';
- const catalog = urlParams.catalog || 'com.linvo.cinemeta:top';
- const category = urlParams.category || '';
- window.location.replace(`#/discover/${type}/${catalog}/${category}`);
- }
- }, [urlParams.type, urlParams.catalog]);
+const Discover = ({ urlParams, queryParams }) => {
+ const [pickers, metaItems] = useCatalog(urlParams, queryParams);
+ const [selectedItem, setSelectedItem] = React.useState(metaItems[0]);
+ const changeMetaItem = React.useCallback((event) => {
+ const metaItem = metaItems.find(({ id }) => id === event.currentTarget.dataset.metaItemId);
+ setSelectedItem(metaItem);
+ }, [metaItems]);
return (
- {
- typeof urlParams.type === 'string' || typeof urlParams.catalog === 'string' ?
-
-
-
-
-
- {urlParams.type}
-
-
-
-
-
-
-
movie
-
-
-
series
-
-
-
channel
-
-
-
TV channels
-
-
-
-
-
-
-
- {urlParams.catalog}
-
-
-
-
-
-
-
catalog1
-
-
-
catalog2
-
-
-
-
-
-
-
- {urlParams.category !== null ? urlParams.category : 'Select category'}
-
-
-
-
-
-
-
category1
-
-
-
category2
-
-
-
-
+
+
+ {pickers.map((picker) => (
+
+ ))}
+
+
+ {metaItems.map((metaItem) => (
+
+
-
- {catalog.map(({ id, type, name, posterShape }) => (
-
-
-
- ))}
-
-
{ }}
- />
-
- :
- null
- }
+ ))}
+
+
+
);
};
diff --git a/src/routes/Discover/PickerMenu.js b/src/routes/Discover/PickerMenu.js
new file mode 100644
index 000000000..302aa8c07
--- /dev/null
+++ b/src/routes/Discover/PickerMenu.js
@@ -0,0 +1,49 @@
+const React = require('react');
+const PropTypes = require('prop-types');
+const classnames = require('classnames');
+const Icon = require('stremio-icons/dom');
+const { Input } = require('stremio-navigation');
+const { Popup, useBinaryState } = require('stremio-common');
+const styles = require('./styles');
+
+// TODO support optionsLimit
+const PickerMenu = ({ name, value, options, toggle }) => {
+ const [open, onOpen, onClose] = useBinaryState(false);
+ const label = typeof value === 'string' ? value : name;
+ return (
+
+
+
+ {label}
+
+
+
+
+
+ {
+ Array.isArray(options) ?
+ options.map(({ value, label }) => (
+
+
{label}
+
+ ))
+ :
+ null
+ }
+
+
+
+ );
+};
+
+PickerMenu.propTypes = {
+ name: PropTypes.string,
+ value: PropTypes.string,
+ options: PropTypes.arrayOf(PropTypes.shape({
+ value: PropTypes.string,
+ label: PropTypes.string
+ })),
+ toggle: PropTypes.func
+};
+
+module.exports = PickerMenu;
diff --git a/src/routes/Discover/styles.less b/src/routes/Discover/styles.less
index 9f715c1e1..7ea7c389f 100644
--- a/src/routes/Discover/styles.less
+++ b/src/routes/Discover/styles.less
@@ -20,29 +20,23 @@
align-self: stretch;
display: grid;
grid-template-columns: 1fr 26em;
- grid-template-rows: 4.6em 1fr;
+ grid-template-rows: auto 1fr;
grid-template-areas:
- "picker-area meta-preview-area"
+ "pickers-area meta-preview-area"
"meta-items-area meta-preview-area";
- overflow: hidden;
.pickers-container {
- grid-area: picker-area;
- display: flex;
- flex-direction: row;
- align-items: stretch;
- padding: 0.8em;
+ grid-area: pickers-area;
+ padding: 0.4em;
.picker-button {
- flex-grow: 0;
- flex-shrink: 1;
- flex-basis: 16em;
- display: flex;
+ width: 16em;
+ height: 3em;
+ margin: 0.4em;
+ padding: 0 0.8em;
+ display: inline-flex;
flex-direction: row;
align-items: center;
- justify-content: space-between;
- margin-right: 0.8em;
- padding: 0 0.8em;
background-color: var(--color-backgroundlighter);
cursor: pointer;
@@ -62,20 +56,16 @@
}
}
- &.types-picker-button {
- .picker-label {
- text-transform: capitalize;
- }
- }
-
.picker-label {
flex: 1;
font-size: 1.1em;
- line-height: 1.1em;
- max-height: 2.2em;
+ line-height: 1.2em;
+ max-height: 2.4em;
color: var(--color-surfacelighter);
- word-break: break-all;
- word-break: break-word;
+
+ &.capitalized {
+ text-transform: capitalize;
+ }
}
.picker-icon {
@@ -90,31 +80,17 @@
.meta-items-container {
grid-area: meta-items-area;
- display: flex;
- flex-direction: row;
- justify-content: flex-start;
- align-content: flex-start;
- flex-wrap: wrap;
padding: 0 0.4em;
overflow-x: hidden;
overflow-y: auto;
- &::after {
- width: 100%;
- height: 0.4em;
- display: block;
- content: "";
- }
-
.meta-item-container {
- flex-grow: 0;
- flex-shrink: 0;
- flex-basis: calc(100% / var(--items-per-row));
+ display: inline-block;
+ width: calc(100% / var(--items-per-row));
padding: 0.4em;
.meta-item {
width: 100%;
- height: 100%;
}
}
}
@@ -130,22 +106,11 @@
--border-color: var(--color-backgroundlighter40);
--box-shadow: -0.6em 0.6em 0.5em -0.1em var(--color-backgrounddark40);
- .menu-items-container {
+ .menu-container {
width: 16em;
- max-height: 18em;
- overflow-y: auto;
background-color: var(--color-backgroundlighter);
- &.menu-types-container {
- .menu-item-container {
- .menu-label {
- text-transform: capitalize;
- }
- }
- }
-
.menu-item-container {
- width: 100%;
padding: 0.8em;
cursor: pointer;
@@ -154,13 +119,14 @@
}
.menu-label {
- line-height: 1.1em;
- max-height: 2.2em;
+ line-height: 1.2em;
+ max-height: 2.4em;
color: var(--color-surfacelighter);
- word-break: break-all;
- word-break: break-word;
+
+ &.capitalized {
+ text-transform: capitalize;
+ }
}
}
}
-
}
\ No newline at end of file
diff --git a/src/routes/Discover/useCatalog.js b/src/routes/Discover/useCatalog.js
index 109a4ca79..8db060faf 100644
--- a/src/routes/Discover/useCatalog.js
+++ b/src/routes/Discover/useCatalog.js
@@ -1,15 +1,104 @@
const React = require('react');
-const useCatalog = (addonId, catalogId, extra) => {
- return React.useMemo(() => {
+const useCatalog = (urlParams, queryParams) => {
+ const query = new URLSearchParams(queryParams).toString();
+ const [addon, catalog] = React.useMemo(() => {
+ // TODO impl this logic to stremio-core for code-reuse:
+ // TODO use type if it is part of user's addons
+ // TODO fallback to first type from user's addons
+ // TODO find catalog for addonId, catalogId and type
+ // TODO fallback to first catalog for the type from user's catalogs
+ const addon = {
+ id: 'com.linvo.cinemeta',
+ version: '2.11.0',
+ name: 'Cinemeta'
+ };
+ const catalog = {
+ id: 'top',
+ type: 'movie',
+ name: 'Top',
+ extra: [
+ {
+ name: 'genre',
+ isRequired: false,
+ options: ['Action', 'drama', 'Boring']
+ },
+ {
+ name: 'year',
+ isRequired: false,
+ options: ['2017', '2016', '2015']
+ }
+ ]
+ };
+ return [addon, catalog];
+ }, [urlParams.type, urlParams.catalog]);
+ const pickers = React.useMemo(() => {
+ const replaceType = (event) => {
+ const { value } = event.currentTarget.dataset;
+ const query = new URLSearchParams(queryParams);
+ window.location = `#/discover/${value}/${addon.id}:${catalog.id}?${query}`;
+ };
+ const replaceCatalog = (event) => {
+ const { value } = event.currentTarget.dataset;
+ const query = new URLSearchParams(queryParams);
+ window.location = `#/discover/${catalog.type}/${value}?${query}`;
+ };
+ const replaceQueryParam = (event) => {
+ const { name, value } = event.currentTarget.dataset;
+ const query = new URLSearchParams({ ...queryParams, [name]: value });
+ window.location = `#/discover/${catalog.type}/${addon.id}:${catalog.id}?${query}`;
+ };
+ const requiredPickers = [
+ {
+ name: 'type',
+ value: catalog.type,
+ options: [
+ { value: 'movie', label: 'movie' },
+ { value: 'series', label: 'series' },
+ { value: 'channels', label: 'channels' },
+ { value: 'games', label: 'games' }
+ ],
+ toggle: replaceType
+ },
+ {
+ name: 'catalog',
+ value: catalog.name,
+ options: [
+ { value: 'com.linvo.cinemeta:top', label: 'Top' },
+ { value: 'com.linvo.cinemeta:year', label: 'By year' }
+ ],
+ toggle: replaceCatalog
+ }
+ ];
+ const extraPickers = catalog.extra
+ .filter((extra) => {
+ return extra.name !== 'skip' && extra.name !== 'search';
+ })
+ .map((extra) => ({
+ ...extra,
+ toggle: replaceQueryParam,
+ options: extra.options.map((option) => ({ value: option, label: option })),
+ value: extra.options.includes(queryParams[extra.name]) ?
+ queryParams[extra.name]
+ :
+ extra.isRequired ?
+ extra.options[0]
+ :
+ null
+ }));
+ return requiredPickers.concat(extraPickers);
+ }, [addon, catalog, query]);
+ const items = React.useMemo(() => {
return Array(303).fill(null).map((_, index) => ({
id: `tt${index}`,
type: 'movie',
- name: 'Stremio demo item',
+ name: `Stremio demo item${index}`,
poster: `https://dummyimage.com/300x400/000/0011ff.jpg&text=${index + 1}`,
+ logo: `https://dummyimage.com/300x400/000/0011ff.jpg&text=${index + 1}`,
posterShape: 'poster'
}));
}, []);
+ return [pickers, items];
};
module.exports = useCatalog;