Mobile UI improvements (#1104)

* Use dropdown for o-counter instead of hover
* Always show previews on non-hoverable device
* Add IntersectionObserver polyfill
* Prevent video previews playing fullscreen
This commit is contained in:
WithoutPants
2021-02-26 16:13:34 +11:00
committed by GitHub
parent af6b21a428
commit a9ac176e91
9 changed files with 98 additions and 60 deletions

View File

@@ -46,6 +46,7 @@
"graphql": "^15.4.0",
"graphql-tag": "^2.11.0",
"i18n-iso-countries": "^6.4.0",
"intersection-observer": "^0.12.0",
"jimp": "^0.16.1",
"localforage": "1.9.0",
"lodash": "^4.17.20",

View File

@@ -1,3 +1,8 @@
### 🎨 Improvements
* Auto-play video previews on mobile devices.
* Replace hover menu with dropdown menu for O-Counter.
* Support random strings for scraper cookie values.
* Added Rescan button to scene, image, gallery details overflow button.
### 🐛 Bug fixes
* Prevent scene card previews playing in full-screen on iOS devices.

View File

@@ -29,17 +29,14 @@ export const ScenePreview: React.FC<IScenePreviewProps> = ({
const videoEl = useRef<HTMLVideoElement>(null);
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.intersectionRatio > 0)
// Catch is necessary due to DOMException if user hovers before clicking on page
videoEl.current?.play().catch(() => {});
else videoEl.current?.pause();
});
},
{ root: document.documentElement }
);
});
if (videoEl.current) observer.observe(videoEl.current);
});
@@ -53,6 +50,8 @@ export const ScenePreview: React.FC<IScenePreviewProps> = ({
<div className={cx("scene-card-preview", { portrait: isPortrait })}>
<img className="scene-card-preview-image" src={image} alt="" />
<video
disableRemotePlayback
playsInline
className="scene-card-preview-video"
loop
preload="none"

View File

@@ -1,6 +1,12 @@
import React from "react";
import { Button, Spinner } from "react-bootstrap";
import { Icon, HoverPopover, SweatDrops } from "src/components/Shared";
import {
Button,
ButtonGroup,
Dropdown,
DropdownButton,
Spinner,
} from "react-bootstrap";
import { Icon, SweatDrops } from "src/components/Shared";
export interface IOCounterButtonProps {
loading: boolean;
@@ -19,7 +25,7 @@ export const OCounterButton: React.FC<IOCounterButtonProps> = (
const renderButton = () => (
<Button
className="minimal"
className="minimal pr-1"
onClick={props.onIncrement}
variant="secondary"
title="O-Counter"
@@ -29,41 +35,32 @@ export const OCounterButton: React.FC<IOCounterButtonProps> = (
</Button>
);
const maybeRenderDropdown = () => {
if (props.value) {
return (
<HoverPopover
content={
<div>
<div>
<Button
className="minimal"
onClick={props.onDecrement}
<DropdownButton
as={ButtonGroup}
title=" "
variant="secondary"
className="pl-0 show-carat"
>
<Dropdown.Item onClick={props.onDecrement}>
<Icon icon="minus" />
<span>Decrement</span>
</Button>
</div>
<div>
<Button
className="minimal"
onClick={props.onReset}
variant="secondary"
>
</Dropdown.Item>
<Dropdown.Item onClick={props.onReset}>
<Icon icon="ban" />
<span>Reset</span>
</Button>
</div>
</div>
}
enterDelay={1000}
placement="bottom"
onOpen={props.onMenuOpened}
onClose={props.onMenuClosed}
>
{renderButton()}
</HoverPopover>
</Dropdown.Item>
</DropdownButton>
);
}
return renderButton();
};
return (
<ButtonGroup className="o-counter">
{renderButton()}
{maybeRenderDropdown()}
</ButtonGroup>
);
};

View File

@@ -209,6 +209,7 @@ textarea.scene-description {
}
}
@media (pointer: fine) {
&:hover {
.scene-specs-overlay,
.rating-banner,
@@ -234,6 +235,26 @@ textarea.scene-description {
}
}
/* replicate hover for non-hoverable interfaces */
@media (hover: none), (pointer: coarse), (pointer: none) {
/* don't hide overlays */
.scene-studio-overlay {
opacity: 0.75;
transition: opacity 0.5s;
}
.scene-card-check {
opacity: 0.75;
transition: opacity 0.5s;
}
.scene-card-preview-video {
top: 0;
transition-delay: 0.2s;
}
}
}
.scene-card.card {
overflow: hidden;
padding: 0;
@@ -545,3 +566,10 @@ input[type="range"].blue-slider {
color: #664c3f;
}
}
.o-counter .dropdown-toggle {
background-color: rgba(0, 0, 0, 0);
border: none;
padding-left: 0;
padding-right: 0.25rem;
}

View File

@@ -57,6 +57,8 @@ const Preview: React.FC<{
);
const video = (
<video
disableRemotePlayback
playsInline
src={previews.video}
poster={previews.image}
autoPlay={previewType === "video"}

View File

@@ -3,6 +3,7 @@ import { shouldPolyfill as shouldPolyfillCanonicalLocales } from "@formatjs/intl
import { shouldPolyfill as shouldPolyfillLocale } from "@formatjs/intl-locale/should-polyfill";
import { shouldPolyfill as shouldPolyfillNumberformat } from "@formatjs/intl-numberformat/should-polyfill";
import { shouldPolyfill as shouldPolyfillPluralRules } from "@formatjs/intl-pluralrules/should-polyfill";
import "intersection-observer/intersection-observer";
// Required for browsers older than August 2020ish. Can be removed at some point.
replaceAll.shim();

View File

@@ -62,7 +62,7 @@ hr {
margin: 5px 0;
}
.dropdown-toggle::after {
:not(.show-carat) > .dropdown-toggle::after {
content: none;
}

View File

@@ -8058,6 +8058,11 @@ internal-slot@^1.0.2:
has "^1.0.3"
side-channel "^1.0.2"
intersection-observer@^0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/intersection-observer/-/intersection-observer-0.12.0.tgz#6c84628f67ce8698e5f9ccf857d97718745837aa"
integrity sha512-2Vkz8z46Dv401zTWudDGwO7KiGHNDkMv417T5ItcNYfmvHR/1qCTVBO9vwH8zZmQ0WkA/1ARwpysR9bsnop4NQ==
intl-messageformat-parser@6.1.3:
version "6.1.3"
resolved "https://registry.yarnpkg.com/intl-messageformat-parser/-/intl-messageformat-parser-6.1.3.tgz#c333850f66d686eca5c9d87eff1ad46f8721b64d"