diff --git a/src/App/App.js b/src/App/App.js
index 21ba1132b..6acb6af28 100644
--- a/src/App/App.js
+++ b/src/App/App.js
@@ -6,7 +6,7 @@ const { useTranslation } = require('react-i18next');
const { Router } = require('stremio-router');
const { Core, Shell, Chromecast, DragAndDrop, KeyboardShortcuts, ServicesProvider } = require('stremio/services');
const { NotFound } = require('stremio/routes');
-const { ToastProvider, TooltipProvider, CONSTANTS, withCoreSuspender } = require('stremio/common');
+const { ToastProvider, TooltipProvider, CONSTANTS, withCoreSuspender, platform } = require('stremio/common');
const ServicesToaster = require('./ServicesToaster');
const DeepLinkHandler = require('./DeepLinkHandler');
const SearchParamsHandler = require('./SearchParamsHandler');
@@ -52,6 +52,14 @@ const App = () => {
window.removeEventListener('hashchange', onLocationHashChange);
};
}, []);
+ React.useEffect(() => {
+ // on mobile and macOS the scrollbars aren't visible when they're not being used,
+ // so we imitate this behavior on those platforms, and fallback to a custom scrollbar on other platforms
+ const osOverlayScrollbar = platform.isMobile() || platform.isMac();
+
+ if (osOverlayScrollbar)
+ document.documentElement.classList.add('os-overlay-scrollbar');
+ }, []);
React.useEffect(() => {
const onCoreStateChanged = () => {
setInitialized(
diff --git a/src/App/styles.less b/src/App/styles.less
index f3dfb4b03..cdbf4d8bd 100644
--- a/src/App/styles.less
+++ b/src/App/styles.less
@@ -58,6 +58,16 @@
box-shadow: none;
overflow: hidden;
word-break: break-word;
+
+ @supports not selector(::-webkit-scrollbar) {
+ scrollbar-width: thin;
+ scrollbar-color: var(--overlay-color) transparent;
+ }
+}
+
+html:global(.os-overlay-scrollbar) {
+ // this makes the browser ignore the custom scrollbar styles when it bahves as an overlay on this platform
+ // and fallbacks to using the OS scrollbar with the given properties when it's not an overlay scrollbar
scrollbar-width: thin;
scrollbar-color: var(--overlay-color) transparent;
}
@@ -130,9 +140,12 @@ html {
z-index: 1;
padding: 0 calc(0.5 * var(--horizontal-nav-bar-size));
overflow-y: auto;
- scrollbar-width: none;
pointer-events: none;
+ @supports not selector(::-webkit-scrollbar) {
+ scrollbar-width: none;
+ }
+
&::-webkit-scrollbar {
display: none;
}
diff --git a/src/common/MainNavBars/MainNavBars.js b/src/common/MainNavBars/MainNavBars.js
index 542d68fe4..ed42840f7 100644
--- a/src/common/MainNavBars/MainNavBars.js
+++ b/src/common/MainNavBars/MainNavBars.js
@@ -14,7 +14,7 @@ const TABS = [
{ id: 'settings', label: 'SETTINGS', icon: 'settings', href: '#/settings' },
];
-const MainNavBars = React.memo(({ className, route, query, children }) => {
+const MainNavBars = React.memo(({ className, route, query, noOverflow, children }) => {
return (
{
selected={route}
tabs={TABS}
/>
- {children}
+ {children}
);
});
@@ -43,7 +43,8 @@ MainNavBars.propTypes = {
className: PropTypes.string,
route: PropTypes.string,
query: PropTypes.string,
- children: PropTypes.node
+ noOverflow: PropTypes.bool,
+ children: PropTypes.node,
};
module.exports = MainNavBars;
diff --git a/src/common/MainNavBars/styles.less b/src/common/MainNavBars/styles.less
index 8515294db..cfdb6970a 100644
--- a/src/common/MainNavBars/styles.less
+++ b/src/common/MainNavBars/styles.less
@@ -40,15 +40,27 @@
--top-overlay-size: calc(var(--horizontal-nav-bar-size) + var(--safe-area-inset-top, 0px));
--bottom-overlay-size: calc(var(--vertical-nav-bar-size) + var(--calculated-bottom-safe-inset, 0px));
- --overlap-size: 3rem;
- --transparency-grandient-pad: 6rem;
+ --overlap-size: 6rem;
+ --transparency-grandient-pad: 2.5rem;
mask: linear-gradient(
to bottom,
transparent calc(var(--top-overlay-size) - var(--overlap-size)),
+ rgba(0, 0, 0, 0.08) calc(var(--top-overlay-size) - (var(--overlap-size) / 2)),
+ rgba(0, 0, 0, 0.16) calc(var(--top-overlay-size) - (var(--overlap-size) / 3)),
black calc(var(--top-overlay-size) + var(--transparency-grandient-pad)),
black 100%
);
+ overflow-x: hidden;
+
+ &::-webkit-scrollbar-track {
+ margin-top: var(--top-overlay-size);
+ }
+
+ &.no-overflow {
+ overflow: clip;
+ overflow: hidden;
+ }
}
}
@@ -61,10 +73,18 @@
mask: linear-gradient(
to bottom,
transparent calc(var(--top-overlay-size) - var(--overlap-size)),
+ rgba(0, 0, 0, 0.08) calc(var(--top-overlay-size) - (var(--overlap-size) / 2)),
+ rgba(0, 0, 0, 0.16) calc(var(--top-overlay-size) - (var(--overlap-size) / 3)),
black calc(var(--top-overlay-size) + var(--transparency-grandient-pad)),
black calc(100% - var(--bottom-overlay-size) - var(--transparency-grandient-pad)),
+ rgba(0, 0, 0, 0.16) calc(100% - var(--bottom-overlay-size) + (var(--overlap-size) / 3)),
+ rgba(0, 0, 0, 0.08) calc(100% - var(--bottom-overlay-size) + (var(--overlap-size) / 2)),
transparent calc(100% - var(--bottom-overlay-size) + var(--overlap-size))
);
+
+ &::-webkit-scrollbar-track {
+ margin-bottom: var(--bottom-overlay-size);
+ }
}
.vertical-nav-bar {
diff --git a/src/common/MetaPreview/styles.less b/src/common/MetaPreview/styles.less
index 1c40127c1..9315bf8de 100644
--- a/src/common/MetaPreview/styles.less
+++ b/src/common/MetaPreview/styles.less
@@ -63,7 +63,13 @@
overflow-y: auto;
&:not(:hover) {
- scrollbar-color: transparent transparent;
+ @supports not selector(::-webkit-scrollbar-thumb) {
+ scrollbar-color: transparent transparent;
+ }
+
+ html:global(.os-overlay-scrollbar) {
+ scrollbar-color: transparent transparent;
+ }
&::-webkit-scrollbar-thumb, &::-webkit-scrollbar-track {
background-color: transparent;
@@ -245,7 +251,14 @@
flex-shrink: 0;
margin-top: 3rem;
overflow: visible;
- scrollbar-width: none;
+
+ @supports not selector(::-webkit-scrollbar) {
+ scrollbar-width: none;
+ }
+
+ html:global(.os-overlay-scrollbar) {
+ scrollbar-width: none;
+ }
&::-webkit-scrollbar {
display: none;
diff --git a/src/common/NavBar/VerticalNavBar/styles.less b/src/common/NavBar/VerticalNavBar/styles.less
index 99e59be93..d91d15e70 100644
--- a/src/common/NavBar/VerticalNavBar/styles.less
+++ b/src/common/NavBar/VerticalNavBar/styles.less
@@ -11,7 +11,14 @@
width: var(--vertical-nav-bar-size);
background-color: transparent;
overflow-y: auto;
- scrollbar-width: none;
+
+ @supports not selector(::-webkit-scrollbar) {
+ scrollbar-width: none;
+ }
+
+ html:global(.os-overlay-scrollbar) {
+ scrollbar-width: none;
+ }
&::-webkit-scrollbar {
display: none;
diff --git a/src/common/platform.js b/src/common/platform.js
index 1e112de6d..2cd13b93a 100644
--- a/src/common/platform.js
+++ b/src/common/platform.js
@@ -19,10 +19,14 @@ const Bowser = require('bowser');
const browser = Bowser.parse(window.navigator?.userAgent || '');
const name = iOS() ? 'ios' : (browser?.os?.name || 'unknown').toLowerCase();
+const osName = browser?.os?.name || 'unknown';
module.exports = {
name,
isMobile: () => {
return name === 'ios' || name === 'android';
+ },
+ isMac: () => {
+ return osName === 'macOS';
}
};
diff --git a/src/routes/Addons/Addons.js b/src/routes/Addons/Addons.js
index c4c99173a..b724cbbe9 100644
--- a/src/routes/Addons/Addons.js
+++ b/src/routes/Addons/Addons.js
@@ -80,7 +80,7 @@ const Addons = ({ urlParams, queryParams }) => {
clearSharedAddon();
}, [urlParams, queryParams]);
return (
-
+
{selectInputs.map((selectInput, index) => (
diff --git a/src/routes/Addons/styles.less b/src/routes/Addons/styles.less
index af4db66ae..c8844177b 100644
--- a/src/routes/Addons/styles.less
+++ b/src/routes/Addons/styles.less
@@ -30,7 +30,7 @@
--top-overlay-size: var(--selectable-inputs-assumed-height);
--bottom-vertical-nav-bar-size: 0px;
--bottom-overlay-size: var(--bottom-vertical-nav-bar-size);
- --overlap-size: 2.5rem;
+ --overlap-size: 6rem;
--transparency-grandient-pad: 3rem;
width: 100%;
@@ -50,10 +50,17 @@
mask: linear-gradient(
to bottom,
transparent calc(var(--top-overlay-size) - var(--overlap-size)),
+ rgba(0, 0, 0, 0.08) calc(var(--top-overlay-size) - (var(--overlap-size) / 2)),
+ rgba(0, 0, 0, 0.16) calc(var(--top-overlay-size) - (var(--overlap-size) / 3)),
black calc(var(--top-overlay-size) + var(--transparency-grandient-pad)),
black 100%
);
z-index: 1;
+
+ &::-webkit-scrollbar-track {
+ margin-top: var(--selectable-inputs-assumed-height);
+ margin-bottom: var(--bottom-overlay-size);
+ }
}
.selectable-inputs-container {
diff --git a/src/routes/Discover/Discover.js b/src/routes/Discover/Discover.js
index 2e2e90beb..8dfca5671 100644
--- a/src/routes/Discover/Discover.js
+++ b/src/routes/Discover/Discover.js
@@ -82,7 +82,7 @@ const Discover = ({ urlParams, queryParams }) => {
setSelectedMetaItemIndex(0);
}, [discover.selected]);
return (
-
+
diff --git a/src/routes/Discover/styles.less b/src/routes/Discover/styles.less
index ea92a4f38..64a1008be 100644
--- a/src/routes/Discover/styles.less
+++ b/src/routes/Discover/styles.less
@@ -32,7 +32,7 @@
--top-overlay-size: var(--selectable-inputs-assumed-height);
--bottom-vertical-nav-bar-size: 0px;
--bottom-overlay-size: var(--bottom-vertical-nav-bar-size);
- --overlap-size: 3rem;
+ --overlap-size: 6rem;
--transparency-grandient-pad: 6rem;
width: 100%;
@@ -58,10 +58,17 @@
mask: linear-gradient(
to bottom,
transparent calc(var(--top-overlay-size) - var(--overlap-size)),
+ rgba(0, 0, 0, 0.08) calc(var(--top-overlay-size) - (var(--overlap-size) / 2)),
+ rgba(0, 0, 0, 0.16) calc(var(--top-overlay-size) - (var(--overlap-size) / 3)),
black calc(var(--top-overlay-size) + var(--transparency-grandient-pad)),
black 100%
);
z-index: 1;
+
+ &::-webkit-scrollbar-track {
+ margin-top: var(--selectable-inputs-assumed-height);
+ margin-bottom: var(--bottom-overlay-size);
+ }
}
.selectable-inputs-container {
diff --git a/src/routes/Library/Library.js b/src/routes/Library/Library.js
index 8f22a0c00..2242dc5c0 100644
--- a/src/routes/Library/Library.js
+++ b/src/routes/Library/Library.js
@@ -62,7 +62,7 @@ const Library = ({ model, urlParams, queryParams }) => {
}
}, [profile.auth, library.selected]);
return (
-
+
{
model === 'continue_watching' || profile.auth !== null ?
diff --git a/src/routes/Library/styles.less b/src/routes/Library/styles.less
index a76eb421d..28b73c753 100644
--- a/src/routes/Library/styles.less
+++ b/src/routes/Library/styles.less
@@ -21,7 +21,7 @@
--top-overlay-size: var(--selectable-inputs-assumed-height);
--bottom-vertical-nav-bar-size: 0px;
--bottom-overlay-size: var(--bottom-vertical-nav-bar-size);
- --overlap-size: 3rem;
+ --overlap-size: 6rem;
--transparency-grandient-pad: 6rem;
width: 100%;
@@ -40,10 +40,17 @@
mask: linear-gradient(
to bottom,
transparent calc(var(--top-overlay-size) - var(--overlap-size)),
+ rgba(0, 0, 0, 0.08) calc(var(--top-overlay-size) - (var(--overlap-size) / 2)),
+ rgba(0, 0, 0, 0.16) calc(var(--top-overlay-size) - (var(--overlap-size) / 3)),
black calc(var(--top-overlay-size) + var(--transparency-grandient-pad)),
black 100%
);
z-index: 1;
+
+ &::-webkit-scrollbar-track {
+ margin-top: var(--selectable-inputs-assumed-height);
+ margin-bottom: var(--bottom-overlay-size);
+ }
}
.selectable-inputs-container {
diff --git a/src/routes/MetaDetails/StreamsList/styles.less b/src/routes/MetaDetails/StreamsList/styles.less
index 6393d5c98..50274d044 100644
--- a/src/routes/MetaDetails/StreamsList/styles.less
+++ b/src/routes/MetaDetails/StreamsList/styles.less
@@ -204,7 +204,14 @@
.streams-container {
margin-top: 0;
- scrollbar-color: @color-surface-light5-20 transparent;
+
+ @supports not selector(::-webkit-scrollbar-thumb) {
+ scrollbar-color: @color-surface-light5-20 transparent;
+ }
+
+ html:global(.os-overlay-scrollbar) {
+ scrollbar-color: @color-surface-light5-20 transparent;
+ }
&::-webkit-scrollbar-thumb {
background-color: @color-surface-light5-20;
diff --git a/src/routes/MetaDetails/styles.less b/src/routes/MetaDetails/styles.less
index 36fff8fd7..e0b8ef32e 100644
--- a/src/routes/MetaDetails/styles.less
+++ b/src/routes/MetaDetails/styles.less
@@ -23,7 +23,7 @@
--navbar-assumed-height: 84px;
--top-overlay-size: var(--navbar-assumed-height);
- --overlap-size: 3rem;
+ --overlap-size: 6rem;
--transparency-grandient-pad: 6rem;
.background-image-layer {
@@ -68,10 +68,16 @@
mask: linear-gradient(
to bottom,
transparent calc(var(--top-overlay-size) - var(--overlap-size)),
+ rgba(0, 0, 0, 0.08) calc(var(--top-overlay-size) - (var(--overlap-size) / 2)),
+ rgba(0, 0, 0, 0.16) calc(var(--top-overlay-size) - (var(--overlap-size) / 3)),
black calc(var(--top-overlay-size) + var(--transparency-grandient-pad)),
black 100%
);
+ &::-webkit-scrollbar-track {
+ margin-top: var(--navbar-assumed-height);
+ }
+
.vertical-nav-bar {
--vertical-nav-bar-size: 6rem;
flex: none;
diff --git a/src/routes/Settings/Settings.js b/src/routes/Settings/Settings.js
index f502a2e31..b2066b144 100644
--- a/src/routes/Settings/Settings.js
+++ b/src/routes/Settings/Settings.js
@@ -193,7 +193,7 @@ const Settings = () => {
closeConfigureServerUrlModal();
}, [routeFocused]);
return (
-
+