mirror of
https://github.com/Stremio/stremio-web.git
synced 2026-04-21 07:32:02 +00:00
library linked with stremio-core
This commit is contained in:
parent
387d72af61
commit
ae3db87fe5
3 changed files with 73 additions and 101 deletions
|
|
@ -1,26 +1,27 @@
|
||||||
const React = require('react');
|
const React = require('react');
|
||||||
const { Dropdown, MainNavBar, MetaItem } = require('stremio/common');
|
const { Multiselect, MainNavBar, MetaItem } = require('stremio/common');
|
||||||
const useLibrary = require('./useLibrary');
|
const useLibrary = require('./useLibrary');
|
||||||
const styles = require('./styles');
|
const styles = require('./styles');
|
||||||
|
|
||||||
const Library = ({ urlParams, queryParams }) => {
|
const Library = ({ urlParams, queryParams }) => {
|
||||||
const [metaItems, dropdowns] = useLibrary(urlParams.type, queryParams.get('sort'));
|
const [metaItems, dropdowns] = useLibrary(urlParams, queryParams);
|
||||||
return (
|
return (
|
||||||
<div className={styles['library-container']}>
|
<div className={styles['library-container']}>
|
||||||
<MainNavBar className={styles['nav-bar']} />
|
<MainNavBar className={styles['nav-bar']} />
|
||||||
<div className={styles['library-content']}>
|
<div className={styles['library-content']}>
|
||||||
<div className={styles['dropdowns-container']}>
|
<div className={styles['dropdowns-container']}>
|
||||||
{dropdowns.map((dropdown) => (
|
{dropdowns.map((dropdown, index) => (
|
||||||
<Dropdown {...dropdown} key={dropdown.name} className={styles['dropdown']} />
|
<Multiselect {...dropdown} key={index} className={styles['dropdown']} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className={styles['meta-items-container']}>
|
<div className={styles['meta-items-container']}>
|
||||||
{metaItems.map((metaItem) => (
|
{metaItems
|
||||||
<MetaItem
|
.map((metaItem, index) => (
|
||||||
{...metaItem}
|
<MetaItem
|
||||||
key={metaItem.id}
|
{...metaItem}
|
||||||
/>
|
key={index}
|
||||||
))}
|
/>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
margin: 2rem;
|
margin: 2rem;
|
||||||
|
overflow: visible;
|
||||||
|
|
||||||
.dropdown {
|
.dropdown {
|
||||||
flex-grow: 0;
|
flex-grow: 0;
|
||||||
|
|
|
||||||
|
|
@ -1,99 +1,69 @@
|
||||||
const React = require('react');
|
const React = require('react');
|
||||||
|
const { useServices } = require('stremio/services');
|
||||||
|
|
||||||
const DEFAULT_TYPE = 'movie';
|
const DEFAULT_TYPE = 'movie';
|
||||||
const libraryItems = [
|
const DEFAULT_SORT = 'recent';
|
||||||
{
|
|
||||||
id: '1',
|
|
||||||
type: 'movie',
|
|
||||||
name: 'Stremio demo item movie 1',
|
|
||||||
poster: '/images/intro_background.jpg',
|
|
||||||
logo: '/images/default_avatar.png',
|
|
||||||
posterShape: 'poster'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '2',
|
|
||||||
type: 'movie',
|
|
||||||
name: 'Stremio demo item movie 2',
|
|
||||||
poster: '/images/intro_background.jpg',
|
|
||||||
logo: '/images/default_avatar.png',
|
|
||||||
posterShape: 'poster'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '3',
|
|
||||||
type: 'series',
|
|
||||||
name: 'Stremio demo item series 1',
|
|
||||||
poster: '/images/default_avatar.png',
|
|
||||||
logo: '/images/default_avatar.png',
|
|
||||||
posterShape: 'poster'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '4',
|
|
||||||
type: 'series',
|
|
||||||
name: 'Stremio demo item series 2',
|
|
||||||
poster: '/images/default_avatar.png',
|
|
||||||
logo: '/images/default_avatar.png',
|
|
||||||
posterShape: 'poster'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '5',
|
|
||||||
type: 'channel',
|
|
||||||
name: 'Stremio demo item channel 1',
|
|
||||||
poster: '/images/anonymous.png',
|
|
||||||
logo: '/images/default_avatar.png',
|
|
||||||
posterShape: 'square'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '6',
|
|
||||||
type: 'channel',
|
|
||||||
name: 'Stremio demo item channel 2',
|
|
||||||
poster: '/images/anonymous.png',
|
|
||||||
logo: '/images/default_avatar.png',
|
|
||||||
posterShape: 'square'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const useLibrary = (type, sort) => {
|
const useLibrary = (urlParams, queryParams) => {
|
||||||
type = typeof type === 'string' && type.length > 0 ? type : DEFAULT_TYPE;
|
const { core } = useServices();
|
||||||
const items = React.useMemo(() => {
|
const [library, setLibrary] = React.useState([[], []]);
|
||||||
return libraryItems.filter(item => item.type === type);
|
|
||||||
}, [type, sort]);
|
React.useEffect(() => {
|
||||||
const onSelect = React.useCallback((event) => {
|
const type = typeof urlParams.type === 'string' && urlParams.type.length > 0 ? urlParams.type : DEFAULT_TYPE;
|
||||||
const { name, value } = event.currentTarget.dataset;
|
const sort = typeof queryParams.get('sort') === 'string' && queryParams.get('sort').length > 0 ? queryParams.get('sort') : DEFAULT_SORT;
|
||||||
if (name === 'type') {
|
const onNewState = () => {
|
||||||
const nextQuery = new URLSearchParams({ sort: typeof sort === 'string' ? sort : '' });
|
const state = core.getState();
|
||||||
const nextType = typeof value === 'string' ? value : '';
|
const sortItems = (items, prop) => {
|
||||||
window.location.replace(`#/library/${nextType}?${nextQuery}`);
|
return items
|
||||||
} else if (name === 'sort') {
|
.filter(item => !item.removed)
|
||||||
const nextQuery = new URLSearchParams({ sort: typeof value === 'string' ? value : '' });
|
.sort((a, b) => {
|
||||||
const nextType = typeof type === 'string' ? type : '';
|
if (a[prop] < b[prop]) return -1;
|
||||||
window.location.replace(`#/library/${nextType}?${nextQuery}`);
|
if (a[prop] > b[prop]) return 1;
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const selectInputs = [
|
||||||
|
{
|
||||||
|
selected: [type],
|
||||||
|
options: state.library.types
|
||||||
|
.map((type) => ({
|
||||||
|
label: type,
|
||||||
|
value: type
|
||||||
|
})),
|
||||||
|
onSelect: (event) => {
|
||||||
|
const value = event.value;
|
||||||
|
const nextQuery = new URLSearchParams({ sort: typeof sort === 'string' ? sort : '' });
|
||||||
|
const nextType = typeof value === 'string' ? value : '';
|
||||||
|
window.location.replace(`#/library/${nextType}?${nextQuery}`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
selected: [sort],
|
||||||
|
options: [{ label: 'A-Z', value: 'a-z' }, { label: 'Recent', value: 'recent' }],
|
||||||
|
onSelect: (event) => {
|
||||||
|
const value = event.value;
|
||||||
|
const nextQuery = new URLSearchParams({ sort: typeof value === 'string' ? value : '' });
|
||||||
|
const nextType = typeof type === 'string' ? type : '';
|
||||||
|
window.location.replace(`#/library/${nextType}?${nextQuery}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
const items = sort === 'recent' ? sortItems(state.library.items, '_ctime') : sortItems(state.library.items, 'name');
|
||||||
|
setLibrary([items, selectInputs]);
|
||||||
}
|
}
|
||||||
}, [type, sort]);
|
core.on('NewModel', onNewState);
|
||||||
const typeDropdown = React.useMemo(() => {
|
core.dispatch({
|
||||||
const selected = typeof type === 'string' && type.length > 0 ? [type] : [];
|
action: 'Load',
|
||||||
const options = libraryItems
|
args: {
|
||||||
.map(({ type }) => type)
|
load: 'LibItemsByType',
|
||||||
.concat(selected)
|
args: type
|
||||||
.filter((type, index, types) => types.indexOf(type) === index)
|
}
|
||||||
.map((type) => ({ label: type, value: type }));
|
});
|
||||||
return {
|
return () => {
|
||||||
name: 'type',
|
core.off('NewModel', onNewState);
|
||||||
selected,
|
|
||||||
options,
|
|
||||||
onSelect
|
|
||||||
};
|
};
|
||||||
}, [type, onSelect]);
|
}, [urlParams, queryParams]);
|
||||||
const sortDropdown = React.useMemo(() => {
|
return library;
|
||||||
const selected = typeof sort === 'string' && sort.length > 0 ? [sort] : [];
|
}
|
||||||
const options = [{ label: 'A-Z', value: 'a-z' }, { label: 'Recent', value: 'recent' }];
|
|
||||||
return {
|
|
||||||
name: 'sort',
|
|
||||||
selected,
|
|
||||||
options,
|
|
||||||
onSelect
|
|
||||||
};
|
|
||||||
}, [sort, onSelect]);
|
|
||||||
return [items, [typeDropdown, sortDropdown]];
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = useLibrary;
|
module.exports = useLibrary;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue