mirror of
https://github.com/Stremio/stremio-web.git
synced 2026-04-19 09:42:13 +00:00
add addon prompt implemented
This commit is contained in:
parent
bb1a4886c3
commit
e9745ea905
5 changed files with 172 additions and 8 deletions
|
|
@ -64,7 +64,7 @@ const NavMenu = ({ className }) => {
|
|||
</Button>
|
||||
<Button className={styles['nav-menu-option-container']} title={'Addons'} href={'#/addons'}>
|
||||
<Icon className={styles['icon']} icon={'ic_addons'} />
|
||||
<div className={styles['nav-menu-option-label']}>Addons</div>
|
||||
<div className={styles['nav-menu-option-label']}>Add-ons</div>
|
||||
</Button>
|
||||
<Button className={styles['nav-menu-option-container']} title={'Remote Control'}>
|
||||
<Icon className={styles['icon']} icon={'ic_remote'} />
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
const React = require('react');
|
||||
const classnames = require('classnames');
|
||||
const Icon = require('stremio-icons/dom');
|
||||
const { Modal } = require('stremio-router');
|
||||
const { Modal, useRouteFocused } = require('stremio-router');
|
||||
const { Button, Multiselect, NavBar, TextInput, SharePrompt } = require('stremio/common');
|
||||
const Addon = require('./Addon');
|
||||
const AddonPrompt = require('./AddonPrompt');
|
||||
|
|
@ -10,16 +10,40 @@ const useSelectedAddon = require('./useSelectedAddon');
|
|||
const styles = require('./styles');
|
||||
|
||||
const Addons = ({ urlParams, queryParams }) => {
|
||||
const inputRef = React.useRef(null);
|
||||
const focusable = useRouteFocused();
|
||||
const [query, setQuery] = React.useState('');
|
||||
const queryOnChange = React.useCallback((event) => {
|
||||
setQuery(event.currentTarget.value);
|
||||
}, []);
|
||||
const [addons, dropdowns, setSelectedAddon, installSelectedAddon, uninstallSelectedAddon, installedAddons] = useAddons(urlParams, queryParams);
|
||||
const [addedAddon, setAddedAddon] = React.useState(false);
|
||||
const [selectedAddon, clearSelectedAddon] = useSelectedAddon(queryParams.get('addon'));
|
||||
const [sharedAddon, setSharedAddon] = React.useState(null);
|
||||
const onAddAddonButtonClicked = React.useCallback(() => {
|
||||
setAddedAddon(true);
|
||||
}, []);
|
||||
const onAddButtonClicked = React.useCallback(() => {
|
||||
setSelectedAddon(inputRef.current.value);
|
||||
setAddedAddon(false);
|
||||
}, [setSelectedAddon]);
|
||||
React.useEffect(() => {
|
||||
const onKeyUp = (event) => {
|
||||
if (event.key === 'Escape' && typeof close === 'function') {
|
||||
setAddedAddon(false);
|
||||
}
|
||||
};
|
||||
if (focusable) {
|
||||
window.addEventListener('keyup', onKeyUp);
|
||||
}
|
||||
return () => {
|
||||
window.removeEventListener('keyup', onKeyUp);
|
||||
};
|
||||
}, [close, focusable]);
|
||||
const promptModalBackgroundOnClick = React.useCallback((event) => {
|
||||
if (!event.nativeEvent.clearSelectedAddonPrevented) {
|
||||
clearSelectedAddon();
|
||||
setAddedAddon(false);
|
||||
setSharedAddon(null);
|
||||
}
|
||||
}, []);
|
||||
|
|
@ -32,12 +56,12 @@ const Addons = ({ urlParams, queryParams }) => {
|
|||
}, [installedAddons]);
|
||||
return (
|
||||
<div className={styles['addons-container']}>
|
||||
<NavBar className={styles['nav-bar']} backButton={true} title={'Addons'} />
|
||||
<NavBar className={styles['nav-bar']} backButton={true} title={'Add-ons'} />
|
||||
<div className={styles['addons-content']}>
|
||||
<div className={styles['top-bar-container']}>
|
||||
<Button className={styles['add-button-container']} title={'Add addon'}>
|
||||
<Button className={styles['add-button-container']} title={'Add add-on'} onClick={onAddAddonButtonClicked}>
|
||||
<Icon className={styles['icon']} icon={'ic_plus'} />
|
||||
<div className={styles['add-button-label']}>Add addon</div>
|
||||
<div className={styles['add-button-label']}>Add add-on</div>
|
||||
</Button>
|
||||
{dropdowns.map((dropdown, index) => (
|
||||
<Multiselect {...dropdown} key={index} className={styles['dropdown']} />
|
||||
|
|
@ -47,7 +71,7 @@ const Addons = ({ urlParams, queryParams }) => {
|
|||
<TextInput
|
||||
className={styles['search-input']}
|
||||
type={'text'}
|
||||
placeholder={'Search addons...'}
|
||||
placeholder={'Search add-ons...'}
|
||||
value={query}
|
||||
onChange={queryOnChange}
|
||||
/>
|
||||
|
|
@ -72,6 +96,32 @@ const Addons = ({ urlParams, queryParams }) => {
|
|||
))
|
||||
}
|
||||
</div>
|
||||
{
|
||||
addedAddon ?
|
||||
<Modal className={styles['prompt-modal-container']} onClick={promptModalBackgroundOnClick}>
|
||||
<div className={classnames(styles['prompt-container'], styles['add-addon-prompt-container'])}>
|
||||
<div className={classnames(styles['prompt'], styles['add-addon-prompt'])} onClick={promptOnClick}>
|
||||
<Button className={styles['close-button-container']} title={'Close'} tabIndex={-1} onClick={() => setAddedAddon(false)}>
|
||||
<Icon className={styles['icon']} icon={'ic_x'} />
|
||||
</Button>
|
||||
<div className={styles['add-addon-prompt-content']}>
|
||||
<div className={styles['add-addon-prompt-label']}>Add add-on</div>
|
||||
<TextInput ref={inputRef} className={styles['url-content']} type={'text'} tabIndex={'-1'} placeholder={'Paste url...'} />
|
||||
<div className={styles['buttons-container']}>
|
||||
<Button className={classnames(styles['button-container'], styles['cancel-button'])} title={'Cancel'} onClick={() => setAddedAddon(false)}>
|
||||
<div className={styles['label']}>Cancel</div>
|
||||
</Button>
|
||||
<Button className={classnames(styles['button-container'], styles['add-button'])} title={'Add'} onClick={onAddButtonClicked}>
|
||||
<div className={styles['label']}>Add</div>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
:
|
||||
null
|
||||
}
|
||||
{
|
||||
selectedAddon !== null ?
|
||||
<Modal className={styles['prompt-modal-container']} onClick={promptModalBackgroundOnClick}>
|
||||
|
|
|
|||
|
|
@ -138,6 +138,119 @@
|
|||
}
|
||||
}
|
||||
|
||||
.add-addon-prompt-container {
|
||||
width: 30rem;
|
||||
|
||||
.add-addon-prompt {
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 2.4rem 0;
|
||||
background-color: var(--color-surfacelighter);
|
||||
|
||||
.close-button-container {
|
||||
position: absolute;
|
||||
top: 0.4rem;
|
||||
right: 0.4rem;
|
||||
z-index: 1;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
padding: 0.4rem;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--color-surfacelight);
|
||||
}
|
||||
|
||||
.icon {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
fill: var(--color-backgrounddarker);
|
||||
}
|
||||
}
|
||||
|
||||
.add-addon-prompt-content {
|
||||
padding: 0 2.4rem;
|
||||
|
||||
.add-addon-prompt-label {
|
||||
margin-bottom: 1.4rem;
|
||||
font-size: 1.3rem;
|
||||
color: var(--color-backgrounddarker);
|
||||
}
|
||||
|
||||
.url-content {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
padding: 0.5rem;
|
||||
font-size: 0.9rem;
|
||||
color: var(--color-surfacedark);
|
||||
border: thin solid var(--color-surface);
|
||||
}
|
||||
|
||||
.buttons-container {
|
||||
flex: none;
|
||||
align-self: stretch;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin-top: 2rem;
|
||||
|
||||
.button-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 3rem;
|
||||
padding: 0 1rem;
|
||||
|
||||
&:first-child {
|
||||
margin-right: 2rem;
|
||||
}
|
||||
|
||||
.label {
|
||||
flex-grow: 0;
|
||||
flex-shrink: 1;
|
||||
flex-basis: auto;
|
||||
max-height: 2.4em;
|
||||
font-size: 1.2rem;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.cancel-button {
|
||||
outline-color: var(--color-surfacedark);
|
||||
outline-style: solid;
|
||||
|
||||
&:hover, &:focus {
|
||||
background-color: var(--color-surfacelight);
|
||||
}
|
||||
|
||||
.label {
|
||||
color: var(--color-backgrounddarker);
|
||||
}
|
||||
}
|
||||
|
||||
.add-button {
|
||||
background-color: var(--color-signal5);
|
||||
|
||||
&:hover, &:focus {
|
||||
filter: brightness(1.2);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline-color: var(--color-surfacedarker);
|
||||
}
|
||||
|
||||
.label {
|
||||
color: var(--color-surfacelighter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.addon-prompt-container {
|
||||
width: 50rem;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,8 @@ const useSelectedAddon = (transportUrl) => {
|
|||
const { pathname, search } = UrlUtils.parse(locationHash.slice(1));
|
||||
const queryParams = new URLSearchParams(search);
|
||||
queryParams.delete('addon');
|
||||
if (!queryParams.values().next().done) {
|
||||
queryParams.delete('null');
|
||||
if ([...queryParams].length !== 0) {
|
||||
window.location.replace(`#${pathname}?${queryParams.toString()}`);
|
||||
}
|
||||
else {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ const StreamsList = ({ className, metaItem }) => {
|
|||
</div>
|
||||
<Button className={styles['install-addons-container']} title={'Install addons'} href={'#/addons'}>
|
||||
<Icon className={styles['icon']} icon={'ic_addons'} />
|
||||
<div className={styles['label']}>Install addons</div>
|
||||
<div className={styles['label']}>Install add-ons</div>
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in a new issue