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 classnames = require('classnames');
const Icon = require('stremio-icons/dom');
const { Button } = require('stremio/common');
const { Button, Image } = require('stremio/common');
const styles = require('./styles');
const Addon = ({ className, id, name, logo, description, types, version, transportUrl, installed, toggle, onShareButtonClicked }) => {
const onKeyUp = React.useCallback((event) => {
if (event.key === 'Enter' && typeof toggle === 'function') {
toggle(event);
const Addon = ({ className, id, name, version, logo, description, types, installed, onToggle, onShare, dataset }) => {
const toggleButtonOnClick = React.useCallback((event) => {
if (typeof onToggle === 'function') {
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 (
<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']}>
{
typeof logo === 'string' && logo.length > 0 ?
<img className={styles['logo']} src={logo} alt={' '} />
:
<Icon className={styles['icon']} icon={'ic_addons'} />
}
<Image
className={styles['logo']}
src={logo}
alt={' '}
renderFallback={renderLogoFallback}
/>
</div>
<div className={styles['info-container']}>
<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
}
{
Array.isArray(types) ?
Array.isArray(types) && types.length > 0 ?
<div className={styles['types-container']}>
{
types.length <= 1 ?
types.length === 1 ?
types.join('')
:
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 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>
</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'} />
<div className={styles['label']}>Share addon</div>
</Button>
@ -68,14 +98,14 @@ Addon.propTypes = {
className: PropTypes.string,
id: PropTypes.string,
name: PropTypes.string,
version: PropTypes.string,
logo: PropTypes.string,
description: PropTypes.string,
types: PropTypes.arrayOf(PropTypes.string),
version: PropTypes.string,
transportUrl: PropTypes.string,
installed: PropTypes.bool,
toggle: PropTypes.func,
onShareButtonClicked: PropTypes.func
onToggle: PropTypes.func,
onShare: PropTypes.func,
dataset: PropTypes.objectOf(PropTypes.string)
};
module.exports = Addon;

View file

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

View file

@ -6,27 +6,32 @@ const useAddons = require('./useAddons');
const useSelectableInputs = require('./useSelectableInputs');
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 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 selectInputs = useSelectableInputs(addons);
const [addAddonModalOpen, openAddAddonModal, closeAddAddonModal] = useBinaryState(false);
const addAddonUrlInputRef = React.useRef(null);
const addAddonOnSubmit = React.useCallback(() => {
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(() => {
return [
{
@ -49,19 +54,23 @@ const Addons = ({ urlParams, queryParams }) => {
setSearch(event.currentTarget.value);
}, []);
const [sharedTransportUrl, setSharedTransportUrl] = React.useState(null);
const shareModalOnClose = React.useCallback(() => {
const clearSharedTransportUrl = React.useCallback(() => {
setSharedTransportUrl(null);
}, []);
const onAddonShare = React.useCallback((event) => {
setSharedTransportUrl(event.dataset.transportUrl);
}, []);
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(() => {
closeAddAddonModal(null);
closeAddAddonModal();
setSearch('');
setSharedTransportUrl(null);
clearSharedTransportUrl();
}, [urlParams, queryParams]);
return (
<div className={styles['addons-container']}>
@ -127,12 +136,13 @@ const Addons = ({ urlParams, queryParams }) => {
className={styles['addon']}
id={addon.manifest.id}
name={addon.manifest.name}
version={addon.manifest.version}
logo={addon.manifest.logo}
description={addon.manifest.description}
types={addon.manifest.types}
version={addon.manifest.version}
onShare={onAddonShare}
installed={addon.installed}
onToggle={onAddonToggle}
onShare={onAddonShare}
dataset={{ transportUrl: addon.transportUrl }}
/>
))
@ -163,8 +173,11 @@ const Addons = ({ urlParams, queryParams }) => {
<ModalDialog
className={styles['share-modal-container']}
title={'Share addon'}
onCloseRequest={shareModalOnClose}>
<SharePrompt className={styles['share-prompt-container']} url={sharedTransportUrl} />
onCloseRequest={clearSharedTransportUrl}>
<SharePrompt
className={styles['share-prompt-container']}
url={sharedTransportUrl}
/>
</ModalDialog>
:
null

View file

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