mirror of
https://github.com/Stremio/stremio-web.git
synced 2026-03-11 21:27:05 +00:00
Addon layout changed
This commit is contained in:
parent
91c692a0c4
commit
3e1ab699f5
4 changed files with 93 additions and 64 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue