mirror of
https://github.com/Stremio/stremio-web.git
synced 2026-04-05 04:19:55 +00:00
sample discover picker linked with stremio core
This commit is contained in:
parent
e7d95a5332
commit
2da642c90a
3 changed files with 102 additions and 100 deletions
|
|
@ -1,14 +1,15 @@
|
|||
const React = require('react');
|
||||
const classnames = require('classnames');
|
||||
const { Dropdown, MainNavBar, MetaItem, MetaPreview } = require('stremio/common');
|
||||
const { MainNavBar, MetaItem, MetaPreview, Multiselect } = require('stremio/common');
|
||||
const useCatalog = require('./useCatalog');
|
||||
const styles = require('./styles');
|
||||
|
||||
// TODO render only 4 pickers and a more button that opens a modal with all pickers
|
||||
const Discover = ({ urlParams, queryParams }) => {
|
||||
const [dropdowns, metaItems] = useCatalog(urlParams, queryParams);
|
||||
const [selectedItem, setSelectedItem] = React.useState(null);
|
||||
const metaItemsOnMouseDown = React.useCallback((event) => {
|
||||
event.nativeEvent.blurPrevented = true;
|
||||
event.nativeEvent.buttonBlurPrevented = true;
|
||||
}, []);
|
||||
const metaItemsOnFocus = React.useCallback((event) => {
|
||||
const metaItem = metaItems.find(({ id }) => {
|
||||
|
|
@ -27,8 +28,8 @@ const Discover = ({ urlParams, queryParams }) => {
|
|||
<MainNavBar className={styles['nav-bar']} />
|
||||
<div className={styles['discover-content']}>
|
||||
<div className={styles['dropdowns-container']}>
|
||||
{dropdowns.map((dropdown) => (
|
||||
<Dropdown {...dropdown} key={dropdown.name} className={styles['dropdown']} />
|
||||
{dropdowns.map((dropdown, index) => (
|
||||
<Multiselect {...dropdown} key={index} className={styles['dropdown']} />
|
||||
))}
|
||||
</div>
|
||||
<div className={styles['meta-items-container']} onFocusCapture={metaItemsOnFocus} onMouseDownCapture={metaItemsOnMouseDown}>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
align-self: stretch;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 26rem;
|
||||
grid-template-rows: fit-content(15rem) 1fr;
|
||||
grid-template-rows: 7rem 1fr;
|
||||
grid-template-areas:
|
||||
"dropdowns-area meta-preview-area"
|
||||
"meta-items-area meta-preview-area";
|
||||
|
|
@ -29,7 +29,7 @@
|
|||
grid-gap: 1rem;
|
||||
margin: 2rem 0;
|
||||
padding: 0 2rem;
|
||||
overflow-y: auto;
|
||||
overflow: visible;
|
||||
|
||||
.dropdown {
|
||||
height: 3rem;
|
||||
|
|
|
|||
|
|
@ -1,104 +1,105 @@
|
|||
const React = require('react');
|
||||
const { useServices } = require('stremio/services');
|
||||
|
||||
const DEFAULT_TYPE = 'movie';
|
||||
const DEFAULT_ADDON_ID = 'com.linvo.cinemeta';
|
||||
const DEFAULT_CATALOG_ID = 'top';
|
||||
|
||||
const useCatalog = (urlParams, queryParams) => {
|
||||
const queryString = 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']
|
||||
const { core } = useServices();
|
||||
const [selectInputs, setSelectInputs] = React.useState([]);
|
||||
React.useEffect(() => {
|
||||
const onNewModel = () => {
|
||||
const state = core.getState();
|
||||
const typeSelectInput = {
|
||||
options: [{ value: urlParams.type, label: urlParams.type }].concat(state.discover.types.map(({ type_name }) => ({
|
||||
value: type_name,
|
||||
label: type_name
|
||||
}))).filter((item, index, array) => {
|
||||
// TODO findIndexRight
|
||||
return array.findIndex(({ value }) => value === item.value) === index;
|
||||
}),
|
||||
selected: [urlParams.type].concat(state.discover.types.filter(({ is_selected }) => is_selected)
|
||||
.map(({ type_name }) => type_name))
|
||||
.filter((item, index, array) => {
|
||||
return array.indexOf(item) === index;
|
||||
}),
|
||||
onSelect: (event) => {
|
||||
const value = event.reactEvent.currentTarget.dataset.value;
|
||||
// TODO queryparams
|
||||
window.location = `#/discover/${value}/${typeof urlParams.catalog === 'string' ? urlParams.catalog : ''}`;
|
||||
}
|
||||
]
|
||||
};
|
||||
console.log(typeSelectInput);
|
||||
setSelectInputs([typeSelectInput]);
|
||||
};
|
||||
return [addon, catalog];
|
||||
}, [urlParams.type, urlParams.catalog]);
|
||||
const dropdowns = React.useMemo(() => {
|
||||
const onTypeChange = (event) => {
|
||||
const { value } = event.currentTarget.dataset;
|
||||
const query = new URLSearchParams(queryParams);
|
||||
window.location = `#/discover/${value}/${addon.id}:${catalog.id}?${query}`;
|
||||
core.on('NewModel', onNewModel);
|
||||
return () => {
|
||||
core.off('NewModel', onNewModel);
|
||||
};
|
||||
const onCatalogChange = (event) => {
|
||||
const { value } = event.currentTarget.dataset;
|
||||
const query = new URLSearchParams(queryParams);
|
||||
window.location = `#/discover/${catalog.type}/${value}?${query}`;
|
||||
};
|
||||
const onQueryParamChange = (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 requiredDropdowns = [
|
||||
{
|
||||
name: 'type',
|
||||
selected: [catalog.type],
|
||||
options: [
|
||||
{ value: 'movie', label: 'movie' },
|
||||
{ value: 'series', label: 'series' },
|
||||
{ value: 'channels', label: 'channels' },
|
||||
{ value: 'games', label: 'games' }
|
||||
],
|
||||
onSelect: onTypeChange
|
||||
},
|
||||
{
|
||||
name: 'catalog',
|
||||
selected: [`${addon.id}:${catalog.id}`],
|
||||
options: [
|
||||
{ value: 'com.linvo.cinemeta:top', label: 'Top' },
|
||||
{ value: 'com.linvo.cinemeta:year', label: 'By year' }
|
||||
],
|
||||
onSelect: onCatalogChange
|
||||
}, [urlParams, queryParams]);
|
||||
React.useEffect(() => {
|
||||
const state = core.getState();
|
||||
let type = DEFAULT_TYPE;
|
||||
let addonId = DEFAULT_ADDON_ID;
|
||||
let catalogId = DEFAULT_CATALOG_ID;
|
||||
if (typeof urlParams.type === 'string' && urlParams.type.length > 0) {
|
||||
type = urlParams.type;
|
||||
addonId = null;
|
||||
catalogId = null;
|
||||
if (typeof urlParams.catalog === 'string' && urlParams.catalog.includes(':')) {
|
||||
[addonId = '', catalogId = ''] = urlParams.catalog.split(':');
|
||||
}
|
||||
];
|
||||
const extraDropdowns = catalog.extra
|
||||
.filter((extra) => {
|
||||
return extra.name !== 'skip' && extra.name !== 'search';
|
||||
})
|
||||
.map((extra) => ({
|
||||
...extra,
|
||||
onSelect: onQueryParamChange,
|
||||
options: extra.options.map((option) => ({ value: option, label: option })),
|
||||
selected: extra.options.includes(queryParams[extra.name]) ?
|
||||
[queryParams[extra.name]]
|
||||
:
|
||||
extra.isRequired ?
|
||||
[extra.options[0]]
|
||||
:
|
||||
[]
|
||||
}));
|
||||
return requiredDropdowns.concat(extraDropdowns);
|
||||
}, [addon, catalog, queryString]);
|
||||
const items = React.useMemo(() => {
|
||||
return Array(100).fill(null).map((_, index) => ({
|
||||
id: `tt${index}`,
|
||||
type: 'movie',
|
||||
name: `Stremio demo item ${index}`,
|
||||
poster: `https://www.stremio.com/website/technology-hero.jpg`,
|
||||
logo: `https://www.stremio.com/website/stremio-logo-small.png`,
|
||||
posterShape: 'poster'
|
||||
}));
|
||||
}, []);
|
||||
return [dropdowns, items];
|
||||
}
|
||||
|
||||
const [addon, catalog] = state.ctx.content.addons.reduceRight((result, addon) => {
|
||||
if (typeof addonId !== 'string' || addonId === addon.manifest.id) {
|
||||
const catalog = addon.manifest.catalogs.find((catalog) => {
|
||||
return (typeof catalogId !== 'string' || catalogId === catalog.id) &&
|
||||
catalog.type === type; // TODO && extraRequired.every(...);
|
||||
});
|
||||
if (catalog) {
|
||||
return [addon, catalog];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}, []);
|
||||
if (catalog) {
|
||||
core.dispatch({
|
||||
action: 'Load',
|
||||
args: {
|
||||
load: 'CatalogFiltered',
|
||||
args: {
|
||||
base: addon.transportUrl,
|
||||
path: {
|
||||
resource: 'catalog',
|
||||
type_name: type,
|
||||
id: catalog.id,
|
||||
extra: [] // TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
core.dispatch({
|
||||
action: 'Load',
|
||||
args: {
|
||||
load: 'CatalogFiltered',
|
||||
args: {
|
||||
base: '',
|
||||
path: {
|
||||
resource: 'catalog',
|
||||
type_name: type,
|
||||
id: '',
|
||||
extra: [] // TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [urlParams, queryParams]);
|
||||
return [selectInputs, []];
|
||||
};
|
||||
|
||||
module.exports = useCatalog;
|
||||
|
|
|
|||
Loading…
Reference in a new issue