mirror of
https://github.com/cheeaun/phanpy.git
synced 2025-03-14 04:08:32 +03:00
Rewrite the <video autoplay> hack for Mobile Safari
- Auto animate when in Status page - Object-fit contain for GIFs in Status page - Add GIF label on timeline
This commit is contained in:
parent
fffc8cc983
commit
5c162d211f
3 changed files with 59 additions and 24 deletions
|
@ -379,7 +379,8 @@
|
|||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
.status .media-video {
|
||||
.status .media-video,
|
||||
.status .media-gif {
|
||||
position: relative;
|
||||
background-clip: padding-box;
|
||||
}
|
||||
|
@ -418,10 +419,27 @@
|
|||
border-radius: 4px;
|
||||
padding: 0 4px;
|
||||
}
|
||||
.status .media-gif[data-label]:not(:hover):after {
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
pointer-events: none;
|
||||
content: attr(data-label);
|
||||
position: absolute;
|
||||
bottom: 8px;
|
||||
left: 8px;
|
||||
color: var(--bg-faded-color);
|
||||
background-color: var(--text-insignificant-color);
|
||||
backdrop-filter: blur(6px) saturate(3) invert(0.2);
|
||||
border-radius: 4px;
|
||||
padding: 0 4px;
|
||||
}
|
||||
.status .media-gif video {
|
||||
object-fit: cover;
|
||||
pointer-events: none;
|
||||
}
|
||||
.status .media-contain video {
|
||||
object-fit: contain !important;
|
||||
}
|
||||
.status .media-audio {
|
||||
border: 0;
|
||||
min-height: 0;
|
||||
|
|
|
@ -29,6 +29,7 @@ import visibilityIconsMap from '../utils/visibility-icons-map';
|
|||
import Avatar from './avatar';
|
||||
import Icon from './icon';
|
||||
import RelativeTime from './relative-time';
|
||||
import Video from './video';
|
||||
|
||||
function fetchAccount(id) {
|
||||
return masto.v1.accounts.fetch(id);
|
||||
|
@ -422,6 +423,7 @@ function Status({
|
|||
<Media
|
||||
key={media.id}
|
||||
media={media}
|
||||
autoAnimate={size === 'l'}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
@ -688,7 +690,7 @@ video = Video clip
|
|||
audio = Audio track
|
||||
*/
|
||||
|
||||
function Media({ media, showOriginal, onClick = () => {} }) {
|
||||
function Media({ media, showOriginal, autoAnimate, onClick = () => {} }) {
|
||||
const { blurhash, description, meta, previewUrl, remoteUrl, url, type } =
|
||||
media;
|
||||
const { original, small, focus } = meta || {};
|
||||
|
@ -758,16 +760,20 @@ function Media({ media, showOriginal, onClick = () => {} }) {
|
|||
const isGIF = type === 'gifv' || shortDuration;
|
||||
const loopable = original.duration <= 60;
|
||||
const formattedDuration = formatDuration(original.duration);
|
||||
const hoverAnimate = !showOriginal && !autoAnimate && isGIF;
|
||||
return (
|
||||
<div
|
||||
class={`media media-${isGIF ? 'gif' : 'video'}`}
|
||||
class={`media media-${isGIF ? 'gif' : 'video'} ${
|
||||
autoAnimate ? 'media-contain' : ''
|
||||
}`}
|
||||
data-formatted-duration={formattedDuration}
|
||||
data-label={isGIF && !showOriginal && !autoAnimate ? 'GIF' : ''}
|
||||
style={{
|
||||
backgroundColor:
|
||||
rgbAverageColor && `rgb(${rgbAverageColor.join(',')})`,
|
||||
}}
|
||||
onClick={(e) => {
|
||||
if (!showOriginal && isGIF) {
|
||||
if (hoverAnimate) {
|
||||
try {
|
||||
videoRef.current.pause();
|
||||
} catch (e) {}
|
||||
|
@ -775,38 +781,32 @@ function Media({ media, showOriginal, onClick = () => {} }) {
|
|||
onClick(e);
|
||||
}}
|
||||
onMouseEnter={() => {
|
||||
if (!showOriginal && isGIF) {
|
||||
if (hoverAnimate) {
|
||||
try {
|
||||
videoRef.current.play();
|
||||
} catch (e) {}
|
||||
}
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
if (!showOriginal && isGIF) {
|
||||
if (hoverAnimate) {
|
||||
try {
|
||||
videoRef.current.pause();
|
||||
} catch (e) {}
|
||||
}
|
||||
}}
|
||||
>
|
||||
{showOriginal ? (
|
||||
<div
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `
|
||||
<video
|
||||
src="${url}"
|
||||
poster="${previewUrl}"
|
||||
width="${width}"
|
||||
height="${height}"
|
||||
preload="auto"
|
||||
autoplay
|
||||
muted="${isGIF}"
|
||||
${isGIF ? '' : 'controls'}
|
||||
playsinline
|
||||
loop="${loopable}"
|
||||
></video>
|
||||
`,
|
||||
}}
|
||||
{showOriginal || autoAnimate ? (
|
||||
<Video
|
||||
src={url}
|
||||
poster={previewUrl}
|
||||
width={width}
|
||||
height={height}
|
||||
preload="auto"
|
||||
autoplay
|
||||
muted={isGIF}
|
||||
controls={!isGIF}
|
||||
playsinline
|
||||
loop={loopable}
|
||||
/>
|
||||
) : isGIF ? (
|
||||
<video
|
||||
|
|
17
src/components/video.jsx
Normal file
17
src/components/video.jsx
Normal file
|
@ -0,0 +1,17 @@
|
|||
// Video component but allow muted attribute to be set
|
||||
import { useEffect, useRef } from 'react';
|
||||
|
||||
function Video({ muted, autoplay, ...props }) {
|
||||
const videoRef = useRef();
|
||||
useEffect(() => {
|
||||
if (videoRef.current) {
|
||||
videoRef.current.setAttribute('muted', muted);
|
||||
videoRef.current.setAttribute('autoplay', autoplay);
|
||||
videoRef.current.play();
|
||||
}
|
||||
}, [muted]);
|
||||
|
||||
return <video ref={videoRef} {...props} />;
|
||||
}
|
||||
|
||||
export default Video;
|
Loading…
Add table
Reference in a new issue