diff --git a/src/common/Dropdown/Dropdown.js b/src/common/Dropdown/Dropdown.js new file mode 100644 index 000000000..6408b0a99 --- /dev/null +++ b/src/common/Dropdown/Dropdown.js @@ -0,0 +1,75 @@ +const React = require('react'); +const PropTypes = require('prop-types'); +const classnames = require('classnames'); +const Icon = require('stremio-icons/dom'); +const Button = require('stremio/common/Button'); +const Popup = require('stremio/common/Popup'); +const useBinaryState = require('stremio/common/useBinaryState'); +const styles = require('./styles'); + +const Dropdown = ({ className, name, selected, options, onSelect }) => { + const [menuOpen, openMenu, closeMenu, toggleMenu] = useBinaryState(false); + const optionOnClick = React.useCallback((event) => { + if (typeof onSelect === 'function') { + onSelect(event); + } + + if (!event.nativeEvent.closeMenuPrevented) { + closeMenu(); + } + }, [onSelect]); + return ( + ( + + )} + renderMenu={() => ( +
+ { + Array.isArray(options) && options.length > 0 ? + options.map(({ label, value }) => ( + + )) + : + null + } +
+ )} + /> + ); +}; + +Dropdown.propTypes = { + className: PropTypes.string, + name: PropTypes.string, + selected: PropTypes.arrayOf(PropTypes.string), + options: PropTypes.arrayOf(PropTypes.shape({ + label: PropTypes.string.isRequired, + value: PropTypes.string.isRequired + })), + onSelect: PropTypes.func +}; + +module.exports = Dropdown; diff --git a/src/common/Dropdown/index.js b/src/common/Dropdown/index.js new file mode 100644 index 000000000..3ac11be07 --- /dev/null +++ b/src/common/Dropdown/index.js @@ -0,0 +1,3 @@ +const Dropdown = require('./Dropdown'); + +module.exports = Dropdown; diff --git a/src/routes/Discover/PickerMenu/styles.less b/src/common/Dropdown/styles.less similarity index 55% rename from src/routes/Discover/PickerMenu/styles.less rename to src/common/Dropdown/styles.less index ea370ab84..f16a66ce4 100644 --- a/src/routes/Discover/PickerMenu/styles.less +++ b/src/common/Dropdown/styles.less @@ -1,8 +1,8 @@ -.picker-label-container { +.dropdown-label-container { display: flex; flex-direction: row; align-items: center; - padding: 0 0.8rem; + padding: 0 1rem; background-color: var(--color-backgroundlighter); &:hover { @@ -12,7 +12,7 @@ &:global(.active) { background-color: var(--color-surfacelight); - .picker-label { + .dropdown-label { color: var(--color-backgrounddarker); } @@ -21,9 +21,8 @@ } } - .picker-label { + .dropdown-label { flex: 1; - font-size: 1.1rem; max-height: 2.4em; color: var(--color-surfacelighter); } @@ -32,24 +31,45 @@ flex: none; width: 1rem; height: 1rem; - margin-left: 0.8rem; + margin-left: 1rem; fill: var(--color-surfacelighter); } } -.picker-menu-container { +.dropdown-menu-container { background-color: var(--color-backgroundlighter); - .picker-option-container { - padding: 0.8rem; + .dropdown-option-container { + display: flex; + flex-direction: row; + align-items: center; + padding: 1rem; + + &:global(.selected) { + background-color: var(--color-surfacedarker40); + + .icon { + display: block; + } + } &:hover { background-color: var(--color-surfacedarker60); } - .picker-option-label { - color: var(--color-surfacelighter); + .dropdown-option-label { + flex: 1; max-height: 4.8em; + color: var(--color-surfacelighter); + } + + .icon { + flex: none; + display: none; + width: 1rem; + height: 1rem; + margin-left: 1rem; + fill: var(--color-surfacelighter); } } } \ No newline at end of file diff --git a/src/common/index.js b/src/common/index.js index da25f6ca4..30c12e39c 100644 --- a/src/common/index.js +++ b/src/common/index.js @@ -1,6 +1,7 @@ const Button = require('./Button'); const Checkbox = require('./Checkbox'); const ColorPicker = require('./ColorPicker'); +const Dropdown = require('./Dropdown'); const MainNavBar = require('./MainNavBar'); const MetaItem = require('./MetaItem'); const MetaPreview = require('./MetaPreview'); @@ -23,6 +24,7 @@ module.exports = { Button, Checkbox, ColorPicker, + Dropdown, MainNavBar, MetaItem, MetaPreview, diff --git a/src/routes/Discover/Discover.js b/src/routes/Discover/Discover.js index 413834713..e060cb12f 100644 --- a/src/routes/Discover/Discover.js +++ b/src/routes/Discover/Discover.js @@ -1,12 +1,11 @@ const React = require('react'); const classnames = require('classnames'); -const { MainNavBar, MetaItem, MetaPreview } = require('stremio/common'); -const PickerMenu = require('./PickerMenu'); +const { Dropdown, MainNavBar, MetaItem, MetaPreview } = require('stremio/common'); const useCatalog = require('./useCatalog'); const styles = require('./styles'); const Discover = ({ urlParams, queryParams }) => { - const [pickers, metaItems] = useCatalog(urlParams, queryParams); + const [dropdowns, metaItems] = useCatalog(urlParams, queryParams); const [selectedItem, setSelectedItem] = React.useState(null); const metaItemsOnMouseDown = React.useCallback((event) => { event.nativeEvent.blurPrevented = true; @@ -27,9 +26,9 @@ const Discover = ({ urlParams, queryParams }) => {
-
- {pickers.map((picker) => ( - +
+ {dropdowns.map((dropdown) => ( + ))}
diff --git a/src/routes/Discover/PickerMenu/PickerMenu.js b/src/routes/Discover/PickerMenu/PickerMenu.js deleted file mode 100644 index 6f3d9f659..000000000 --- a/src/routes/Discover/PickerMenu/PickerMenu.js +++ /dev/null @@ -1,59 +0,0 @@ -const React = require('react'); -const PropTypes = require('prop-types'); -const classnames = require('classnames'); -const Icon = require('stremio-icons/dom'); -const { Button, Popup, useBinaryState } = require('stremio/common'); -const styles = require('./styles'); - -const PickerMenu = ({ className, name, value, options, onSelect }) => { - const [menuOpen, openMenu, closeMenu, toggleMenu] = useBinaryState(false); - const optionOnClick = React.useCallback((event) => { - if (typeof onSelect === 'function') { - onSelect(event); - } - - if (!event.nativeEvent.closeMenuPrevented) { - closeMenu(); - } - }, [onSelect]); - return ( - ( - - )} - renderMenu={() => ( -
- { - Array.isArray(options) && options.length > 0 ? - options.map(({ label, value }) => ( - - )) - : - null - } -
- )} - /> - ); -}; - -PickerMenu.propTypes = { - className: PropTypes.string, - name: PropTypes.string, - value: PropTypes.string, - options: PropTypes.arrayOf(PropTypes.shape({ - label: PropTypes.string, - value: PropTypes.string.isRequired - })), - onSelect: PropTypes.func -}; - -module.exports = PickerMenu; diff --git a/src/routes/Discover/PickerMenu/index.js b/src/routes/Discover/PickerMenu/index.js deleted file mode 100644 index be50183b7..000000000 --- a/src/routes/Discover/PickerMenu/index.js +++ /dev/null @@ -1,3 +0,0 @@ -const PickerMenu = require('./PickerMenu'); - -module.exports = PickerMenu; diff --git a/src/routes/Discover/styles.less b/src/routes/Discover/styles.less index 94d6bfe94..ba94de02e 100644 --- a/src/routes/Discover/styles.less +++ b/src/routes/Discover/styles.less @@ -19,18 +19,18 @@ grid-template-columns: 1fr 26rem; grid-template-rows: fit-content(15rem) 1fr; grid-template-areas: - "pickers-area meta-preview-area" + "dropdowns-area meta-preview-area" "meta-items-area meta-preview-area"; - .pickers-container { - grid-area: pickers-area; + .dropdowns-container { + grid-area: dropdowns-area; display: grid; grid-gap: 1rem; margin: 2rem 0; padding: 0 2rem; overflow-y: auto; - .picker { + .dropdown { height: 3rem; } } @@ -62,7 +62,7 @@ @media only screen and (min-width: @xxlarge) { .discover-container { .discover-content { - .pickers-container { + .dropdowns-container { grid-template-columns: repeat(auto-fill, 17rem); } @@ -76,7 +76,7 @@ @media only screen and (max-width: @xxlarge) { .discover-container { .discover-content { - .pickers-container { + .dropdowns-container { grid-template-columns: repeat(6, 1fr); } @@ -90,7 +90,7 @@ @media only screen and (max-width: @normal) { .discover-container { .discover-content { - .pickers-container { + .dropdowns-container { grid-template-columns: repeat(5, 1fr); } @@ -104,7 +104,7 @@ @media only screen and (max-width: @medium) { .discover-container { .discover-content { - .pickers-container { + .dropdowns-container { grid-template-columns: repeat(4, 1fr); } @@ -118,7 +118,7 @@ @media only screen and (max-width: @small) { .discover-container { .discover-content { - .pickers-container { + .dropdowns-container { grid-template-columns: repeat(3, 1fr); } @@ -135,10 +135,10 @@ grid-template-columns: 1fr; grid-template-rows: fit-content(19rem) 1fr; grid-template-areas: - "pickers-area" + "dropdowns-area" "meta-items-area"; - .pickers-container { + .dropdowns-container { grid-template-columns: repeat(4, 1fr); } @@ -157,7 +157,7 @@ @media only screen and (max-width: @minimum) { .discover-container { .discover-content { - .pickers-container { + .dropdowns-container { grid-template-columns: repeat(3, 1fr); } } diff --git a/src/routes/Discover/useCatalog.js b/src/routes/Discover/useCatalog.js index fcf3028ae..77dc11da4 100644 --- a/src/routes/Discover/useCatalog.js +++ b/src/routes/Discover/useCatalog.js @@ -32,7 +32,7 @@ const useCatalog = (urlParams, queryParams) => { }; return [addon, catalog]; }, [urlParams.type, urlParams.catalog]); - const pickers = React.useMemo(() => { + const dropdowns = React.useMemo(() => { const onTypeChange = (event) => { const { value } = event.currentTarget.dataset; const query = new URLSearchParams(queryParams); @@ -48,45 +48,45 @@ const useCatalog = (urlParams, queryParams) => { const query = new URLSearchParams({ ...queryParams, [name]: value }); window.location = `#/discover/${catalog.type}/${addon.id}:${catalog.id}?${query}`; }; - const requiredPickers = [ + const requiredDropdowns = [ { name: 'type', - value: catalog.type, + selected: [catalog.type], options: [ { value: 'movie', label: 'movie' }, { value: 'series', label: 'series' }, { value: 'channels', label: 'channels' }, { value: 'games', label: 'games' } ], - onChange: onTypeChange + onSelect: onTypeChange }, { name: 'catalog', - value: catalog.name, + selected: [`${addon.id}:${catalog.id}`], options: [ { value: 'com.linvo.cinemeta:top', label: 'Top' }, { value: 'com.linvo.cinemeta:year', label: 'By year' } ], - onChange: onCatalogChange + onSelect: onCatalogChange } ]; - const extraPickers = catalog.extra + const extraDropdowns = catalog.extra .filter((extra) => { return extra.name !== 'skip' && extra.name !== 'search'; }) .map((extra) => ({ ...extra, - onChange: onQueryParamChange, + onSelect: onQueryParamChange, options: extra.options.map((option) => ({ value: option, label: option })), - value: extra.options.includes(queryParams[extra.name]) ? - queryParams[extra.name] + selected: extra.options.includes(queryParams[extra.name]) ? + [queryParams[extra.name]] : extra.isRequired ? - extra.options[0] + [extra.options[0]] : - null + [] })); - return requiredPickers.concat(extraPickers); + return requiredDropdowns.concat(extraDropdowns); }, [addon, catalog, queryString]); const items = React.useMemo(() => { return Array(100).fill(null).map((_, index) => ({ @@ -98,7 +98,7 @@ const useCatalog = (urlParams, queryParams) => { posterShape: 'poster' })); }, []); - return [pickers, items]; + return [dropdowns, items]; }; module.exports = useCatalog;