Addon layout changed

This commit is contained in:
NikolaBorislavovHristov 2019-12-15 01:38:16 +02:00
parent 91c692a0c4
commit 3e1ab699f5
4 changed files with 93 additions and 64 deletions

View file

@ -2,24 +2,54 @@ const React = require('react');
const PropTypes = require('prop-types'); const PropTypes = require('prop-types');
const classnames = require('classnames'); const classnames = require('classnames');
const Icon = require('stremio-icons/dom'); const Icon = require('stremio-icons/dom');
const { Button } = require('stremio/common'); const { Button, Image } = require('stremio/common');
const styles = require('./styles'); const styles = require('./styles');
const Addon = ({ className, id, name, logo, description, types, version, transportUrl, installed, toggle, onShareButtonClicked }) => { const Addon = ({ className, id, name, version, logo, description, types, installed, onToggle, onShare, dataset }) => {
const onKeyUp = React.useCallback((event) => { const toggleButtonOnClick = React.useCallback((event) => {
if (event.key === 'Enter' && typeof toggle === 'function') { if (typeof onToggle === 'function') {
toggle(event); onToggle({
type: 'toggle',
nativeEvent: event.nativeEvent,
reactEvent: event,
dataset: dataset
});
} }
}, [toggle]); }, [onToggle, dataset]);
const shareButtonOnClick = React.useCallback((event) => {
if (typeof onShare === 'function') {
onShare({
type: 'share',
nativeEvent: event.nativeEvent,
reactEvent: event,
dataset: dataset
});
}
}, [onShare, dataset]);
const onKeyDown = React.useCallback((event) => {
if (event.key === 'Enter' && typeof onToggle === 'function') {
onToggle({
type: 'toggle',
nativeEvent: event.nativeEvent,
reactEvent: event,
dataset: dataset
});
}
}, [onToggle, dataset]);
const renderLogoFallback = React.useMemo(() => () => {
return (
<Icon className={styles['icon']} icon={'ic_addons'} />
);
}, []);
return ( return (
<Button className={classnames(styles['addon-container'], className)} data-id={id} onKeyUp={onKeyUp}> <Button className={classnames(className, styles['addon-container'])} onKeyDown={onKeyDown}>
<div className={styles['logo-container']}> <div className={styles['logo-container']}>
{ <Image
typeof logo === 'string' && logo.length > 0 ? className={styles['logo']}
<img className={styles['logo']} src={logo} alt={' '} /> src={logo}
: alt={' '}
<Icon className={styles['icon']} icon={'ic_addons'} /> renderFallback={renderLogoFallback}
} />
</div> </div>
<div className={styles['info-container']}> <div className={styles['info-container']}>
<div className={styles['name-container']} title={typeof name === 'string' && name.length > 0 ? name : id}> <div className={styles['name-container']} title={typeof name === 'string' && name.length > 0 ? name : id}>
@ -32,10 +62,10 @@ const Addon = ({ className, id, name, logo, description, types, version, transpo
null null
} }
{ {
Array.isArray(types) ? Array.isArray(types) && types.length > 0 ?
<div className={styles['types-container']}> <div className={styles['types-container']}>
{ {
types.length <= 1 ? types.length === 1 ?
types.join('') types.join('')
: :
types.slice(0, -1).join(', ') + ' & ' + types[types.length - 1] types.slice(0, -1).join(', ') + ' & ' + types[types.length - 1]
@ -52,10 +82,10 @@ const Addon = ({ className, id, name, logo, description, types, version, transpo
} }
</div> </div>
<div className={styles['buttons-container']}> <div className={styles['buttons-container']}>
<Button className={installed ? styles['uninstall-button-container'] : styles['install-button-container']} title={installed ? 'Uninstall' : 'Install'} tabIndex={-1} data-id={id} onClick={toggle}> <Button className={installed ? styles['uninstall-button-container'] : styles['install-button-container']} title={installed ? 'Uninstall' : 'Install'} tabIndex={-1} onClick={toggleButtonOnClick}>
<div className={styles['label']}>{installed ? 'Uninstall' : 'Install'}</div> <div className={styles['label']}>{installed ? 'Uninstall' : 'Install'}</div>
</Button> </Button>
<Button className={styles['share-button-container']} title={'Share addon'} tabIndex={-1} onClick={onShareButtonClicked}> <Button className={styles['share-button-container']} title={'Share addon'} tabIndex={-1} onClick={shareButtonOnClick}>
<Icon className={styles['icon']} icon={'ic_share'} /> <Icon className={styles['icon']} icon={'ic_share'} />
<div className={styles['label']}>Share addon</div> <div className={styles['label']}>Share addon</div>
</Button> </Button>
@ -68,14 +98,14 @@ Addon.propTypes = {
className: PropTypes.string, className: PropTypes.string,
id: PropTypes.string, id: PropTypes.string,
name: PropTypes.string, name: PropTypes.string,
version: PropTypes.string,
logo: PropTypes.string, logo: PropTypes.string,
description: PropTypes.string, description: PropTypes.string,
types: PropTypes.arrayOf(PropTypes.string), types: PropTypes.arrayOf(PropTypes.string),
version: PropTypes.string,
transportUrl: PropTypes.string,
installed: PropTypes.bool, installed: PropTypes.bool,
toggle: PropTypes.func, onToggle: PropTypes.func,
onShareButtonClicked: PropTypes.func onShare: PropTypes.func,
dataset: PropTypes.objectOf(PropTypes.string)
}; };
module.exports = Addon; module.exports = Addon;

View file

@ -1,7 +1,6 @@
.addon-container { .addon-container {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
flex-wrap: wrap;
align-items: flex-start; align-items: flex-start;
padding: 1rem; padding: 1rem;
background-color: var(--color-backgroundlighter); background-color: var(--color-backgroundlighter);
@ -17,6 +16,7 @@
display: block; display: block;
width: 100%; width: 100%;
height: 100%; height: 100%;
padding: 0.5rem;
object-fit: contain; object-fit: contain;
object-position: center; object-position: center;
} }
@ -31,14 +31,13 @@
} }
.info-container { .info-container {
flex-grow: 1000; flex-grow: 1;
flex-shrink: 1; flex-shrink: 1;
flex-basis: 0; flex-basis: 0;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
flex-wrap: wrap; flex-wrap: wrap;
align-items: baseline; align-items: baseline;
min-width: 40rem;
padding: 0 0.5rem; padding: 0 0.5rem;
.name-container { .name-container {
@ -47,7 +46,7 @@
flex-basis: auto; flex-basis: auto;
padding: 0 0.5rem; padding: 0 0.5rem;
max-height: 3.6em; max-height: 3.6em;
font-size: 1.5rem; font-size: 1.6rem;
color: var(--color-surfacelighter); color: var(--color-surfacelighter);
} }
@ -55,6 +54,7 @@
flex-grow: 1; flex-grow: 1;
flex-shrink: 1; flex-shrink: 1;
flex-basis: auto; flex-basis: auto;
margin-top: 0.5rem;
padding: 0 0.5rem; padding: 0 0.5rem;
max-height: 2.4em; max-height: 2.4em;
color: var(--color-surfacelight); color: var(--color-surfacelight);
@ -83,22 +83,14 @@
} }
.buttons-container { .buttons-container {
flex-grow: 1; flex: none;
flex-shrink: 0; width: 17rem;
flex-basis: 0;
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: flex-end;
min-width: 17rem;
.install-button-container, .uninstall-button-container, .share-button-container { .install-button-container, .uninstall-button-container, .share-button-container {
flex: none;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 17rem;
height: 3.5rem; height: 3.5rem;
padding: 0 1rem; padding: 0 1rem;
@ -106,13 +98,8 @@
margin-top: 1rem; margin-top: 1rem;
} }
&:not(:last-child) {
margin-right: 1rem;
}
.icon { .icon {
flex: none; flex: none;
display: block;
width: 1.5rem; width: 1.5rem;
height: 1.5rem; height: 1.5rem;
margin-right: 1rem; margin-right: 1rem;

View file

@ -6,27 +6,32 @@ const useAddons = require('./useAddons');
const useSelectableInputs = require('./useSelectableInputs'); const useSelectableInputs = require('./useSelectableInputs');
const styles = require('./styles'); const styles = require('./styles');
const navigateToAddonDetails = (addonsCatalogRequest, transportUrl) => {
const queryParams = new URLSearchParams([['addon', transportUrl]]);
if (addonsCatalogRequest !== null) {
const addonTransportUrl = encodeURIComponent(addonsCatalogRequest.base);
const catalogId = encodeURIComponent(addonsCatalogRequest.path.id);
const type = encodeURIComponent(addonsCatalogRequest.path.type_name);
window.location.replace(`#/addons/${addonTransportUrl}/${catalogId}/${type}?${queryParams}`);
} else {
window.location.replace(`#/addons?${queryParams}`);
}
};
const Addons = ({ urlParams, queryParams }) => { const Addons = ({ urlParams, queryParams }) => {
const navigateToAddonDetails = React.useCallback((transportUrl) => {
const queryParams = new URLSearchParams([['addon', transportUrl]]);
if (typeof urlParams.addonTransportUrl === 'string' && typeof urlParams.catalogId === 'string' && typeof urlParams.type === 'string') {
const addonTransportUrl = encodeURIComponent(urlParams.addonTransportUrl);
const catalogId = encodeURIComponent(urlParams.catalogId);
const type = encodeURIComponent(urlParams.type);
window.location.replace(`#/addons/${addonTransportUrl}/${catalogId}/${type}?${queryParams}`);
} else {
window.location.replace(`#/addons?${queryParams}`);
}
}, [urlParams]);
const addons = useAddons(urlParams); const addons = useAddons(urlParams);
const selectInputs = useSelectableInputs(addons); const selectInputs = useSelectableInputs(addons);
const [addAddonModalOpen, openAddAddonModal, closeAddAddonModal] = useBinaryState(false); const [addAddonModalOpen, openAddAddonModal, closeAddAddonModal] = useBinaryState(false);
const addAddonUrlInputRef = React.useRef(null); const addAddonUrlInputRef = React.useRef(null);
const addAddonOnSubmit = React.useCallback(() => { const addAddonOnSubmit = React.useCallback(() => {
if (addAddonUrlInputRef.current !== null) { if (addAddonUrlInputRef.current !== null) {
navigateToAddonDetails(addAddonUrlInputRef.current.value); const addonsCatalogRequest = addons.catalog_resource !== null ?
addons.catalog_resource.request
:
null;
navigateToAddonDetails(addonsCatalogRequest, addAddonUrlInputRef.current.value);
} }
}, [navigateToAddonDetails]); }, [addons]);
const addAddonModalButtons = React.useMemo(() => { const addAddonModalButtons = React.useMemo(() => {
return [ return [
{ {
@ -49,19 +54,23 @@ const Addons = ({ urlParams, queryParams }) => {
setSearch(event.currentTarget.value); setSearch(event.currentTarget.value);
}, []); }, []);
const [sharedTransportUrl, setSharedTransportUrl] = React.useState(null); const [sharedTransportUrl, setSharedTransportUrl] = React.useState(null);
const shareModalOnClose = React.useCallback(() => { const clearSharedTransportUrl = React.useCallback(() => {
setSharedTransportUrl(null); setSharedTransportUrl(null);
}, []); }, []);
const onAddonShare = React.useCallback((event) => { const onAddonShare = React.useCallback((event) => {
setSharedTransportUrl(event.dataset.transportUrl); setSharedTransportUrl(event.dataset.transportUrl);
}, []); }, []);
const onAddonToggle = React.useCallback((event) => { const onAddonToggle = React.useCallback((event) => {
navigateToAddonDetails(event.dataset.transportUrl); const addonsCatalogRequest = addons.catalog_resource !== null ?
}, []); addons.catalog_resource.request
:
null;
navigateToAddonDetails(addonsCatalogRequest, event.dataset.transportUrl);
}, [addons]);
React.useLayoutEffect(() => { React.useLayoutEffect(() => {
closeAddAddonModal(null); closeAddAddonModal();
setSearch(''); setSearch('');
setSharedTransportUrl(null); clearSharedTransportUrl();
}, [urlParams, queryParams]); }, [urlParams, queryParams]);
return ( return (
<div className={styles['addons-container']}> <div className={styles['addons-container']}>
@ -127,12 +136,13 @@ const Addons = ({ urlParams, queryParams }) => {
className={styles['addon']} className={styles['addon']}
id={addon.manifest.id} id={addon.manifest.id}
name={addon.manifest.name} name={addon.manifest.name}
version={addon.manifest.version}
logo={addon.manifest.logo} logo={addon.manifest.logo}
description={addon.manifest.description} description={addon.manifest.description}
types={addon.manifest.types} types={addon.manifest.types}
version={addon.manifest.version} installed={addon.installed}
onShare={onAddonShare}
onToggle={onAddonToggle} onToggle={onAddonToggle}
onShare={onAddonShare}
dataset={{ transportUrl: addon.transportUrl }} dataset={{ transportUrl: addon.transportUrl }}
/> />
)) ))
@ -163,8 +173,11 @@ const Addons = ({ urlParams, queryParams }) => {
<ModalDialog <ModalDialog
className={styles['share-modal-container']} className={styles['share-modal-container']}
title={'Share addon'} title={'Share addon'}
onCloseRequest={shareModalOnClose}> onCloseRequest={clearSharedTransportUrl}>
<SharePrompt className={styles['share-prompt-container']} url={sharedTransportUrl} /> <SharePrompt
className={styles['share-prompt-container']}
url={sharedTransportUrl}
/>
</ModalDialog> </ModalDialog>
: :
null null

View file

@ -30,8 +30,7 @@ const mapAddonsStateWithCtx = (addons, ctx) => {
version: descriptor.manifest.version, version: descriptor.manifest.version,
logo: descriptor.manifest.logo, logo: descriptor.manifest.logo,
description: descriptor.manifest.description, description: descriptor.manifest.description,
types: descriptor.manifest.types, types: descriptor.manifest.types
catalogs: descriptor.manifest.catalogs,
} }
})) }))
} }