3
0
mirror of https://github.com/Qortal/q-tube.git synced 2025-02-11 09:45:51 +00:00

Merge pull request #55 from QortalSeth/main

Updates to VideoPlayer controls
This commit is contained in:
Qortal Dev 2024-12-20 10:22:57 -07:00 committed by GitHub
commit 84c07b07cd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 440 additions and 304 deletions

20
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "qtube",
"version": "2.0.0",
"version": "2.1.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "qtube",
"version": "2.0.0",
"version": "2.1.0",
"dependencies": {
"@emotion/react": "^11.10.6",
"@emotion/styled": "^11.10.6",
@ -23,6 +23,7 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-dropzone": "^14.2.3",
"react-idle-timer": "^5.7.2",
"react-intersection-observer": "^9.4.3",
"react-quill": "^2.0.0",
"react-redux": "^8.0.5",
@ -3958,6 +3959,15 @@
"react": ">= 16.8 || 18.0.0"
}
},
"node_modules/react-idle-timer": {
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/react-idle-timer/-/react-idle-timer-5.7.2.tgz",
"integrity": "sha512-+BaPfc7XEUU5JFkwZCx6fO1bLVK+RBlFH+iY4X34urvIzZiZINP6v2orePx3E6pAztJGE7t4DzvL7if2SL/0GQ==",
"peerDependencies": {
"react": ">=16",
"react-dom": ">=16"
}
},
"node_modules/react-intersection-observer": {
"version": "9.5.0",
"resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.5.0.tgz",
@ -7321,6 +7331,12 @@
"prop-types": "^15.8.1"
}
},
"react-idle-timer": {
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/react-idle-timer/-/react-idle-timer-5.7.2.tgz",
"integrity": "sha512-+BaPfc7XEUU5JFkwZCx6fO1bLVK+RBlFH+iY4X34urvIzZiZINP6v2orePx3E6pAztJGE7t4DzvL7if2SL/0GQ==",
"requires": {}
},
"react-intersection-observer": {
"version": "9.5.0",
"resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.5.0.tgz",

View File

@ -25,6 +25,7 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-dropzone": "^14.2.3",
"react-idle-timer": "^5.7.2",
"react-intersection-observer": "^9.4.3",
"react-quill": "^2.0.0",
"react-redux": "^8.0.5",

View File

@ -1,109 +0,0 @@
import {
Fullscreen,
MoreVert as MoreIcon,
Pause,
PictureInPicture,
PlayArrow,
Refresh,
VolumeUp,
} from "@mui/icons-material";
import { IconButton, Menu, MenuItem, Slider, Typography } from "@mui/material";
import { useVideoContext } from "./VideoContext.ts";
export const MobileControls = () => {
const {
togglePlay,
reloadVideo,
onProgressChange,
videoRef,
handleMenuOpen,
handleMenuClose,
onVolumeChange,
increaseSpeed,
togglePictureInPicture,
toggleFullscreen,
playing,
progress,
anchorEl,
volume,
playbackRate,
} = useVideoContext();
return (
<>
<IconButton
sx={{
color: "rgba(255, 255, 255, 0.7)",
}}
onClick={() => togglePlay()}
>
{playing.value ? <Pause /> : <PlayArrow />}
</IconButton>
<IconButton
sx={{
color: "rgba(255, 255, 255, 0.7)",
}}
onClick={reloadVideo}
>
<Refresh />
</IconButton>
<Slider
value={progress.value}
onChange={onProgressChange}
min={0}
max={videoRef.current?.duration || 100}
sx={{ flexGrow: 1, mx: 2 }}
/>
<Typography
sx={{
color: "rgba(255, 255, 255, 0.7)",
fontSize: "14px",
userSelect: "none",
minWidth: "30px",
}}
onClick={() => increaseSpeed()}
>
{playbackRate}x
</Typography>
<Fullscreen onClick={toggleFullscreen} />
<IconButton
edge="end"
color="inherit"
aria-label="menu"
onClick={handleMenuOpen}
sx={{ minWidth: "30px" }}
>
<MoreIcon />
</IconButton>
<Menu
id="simple-menu"
anchorEl={anchorEl.value}
keepMounted
open={Boolean(anchorEl.value)}
onClose={handleMenuClose}
PaperProps={{
style: {
width: "250px",
},
}}
>
<MenuItem>
<VolumeUp />
<Slider
value={volume.value}
onChange={onVolumeChange}
min={0}
max={1}
step={0.01}
/>
</MenuItem>
<MenuItem onClick={togglePictureInPicture}>
<PictureInPicture />
</MenuItem>
</Menu>
</>
);
};

View File

@ -0,0 +1,66 @@
import { MoreVert as MoreIcon } from "@mui/icons-material";
import { Box, IconButton, Menu, MenuItem } from "@mui/material";
import { useVideoContext } from "./VideoContext.ts";
import {
FullscreenButton,
PictureInPictureButton,
PlaybackRate,
PlayButton,
ProgressSlider,
ReloadButton,
VideoTime,
VolumeButton,
VolumeSlider,
} from "./VideoControls.tsx";
export const MobileControlsBar = () => {
const { handleMenuOpen, handleMenuClose, anchorEl } = useVideoContext();
const controlGroupSX = { display: "flex", gap: "5px", alignItems: "center" };
return (
<>
<Box sx={controlGroupSX}>
<PlayButton />
<ReloadButton />
<ProgressSlider />
<VideoTime />
</Box>
<Box sx={controlGroupSX}>
<PlaybackRate />
<FullscreenButton />
<IconButton
edge="end"
color="inherit"
aria-label="menu"
onClick={handleMenuOpen}
sx={{ minWidth: "30px", paddingLeft: "0px" }}
>
<MoreIcon />
</IconButton>
</Box>
<Menu
id="simple-menu"
anchorEl={anchorEl.value}
keepMounted
open={Boolean(anchorEl.value)}
onClose={handleMenuClose}
PaperProps={{
style: {
width: "250px",
},
}}
>
<MenuItem>
<VolumeButton />
<VolumeSlider />
</MenuItem>
<MenuItem>
<PictureInPictureButton />
</MenuItem>
</Menu>
</>
);
};

View File

@ -5,16 +5,8 @@ import { useEffect } from "react";
import ReactDOM from "react-dom";
import { useDispatch, useSelector } from "react-redux";
import { Key } from "ts-key-enum";
import { useIsMobile } from "../../../../hooks/useIsMobile.ts";
import { setVideoPlaying } from "../../../../state/features/globalSlice.ts";
import {
setIsMuted,
setMutedVolumeSetting,
setReduxPlaybackRate,
setStretchVideoSetting,
setVolumeSetting,
} from "../../../../state/features/persistSlice.ts";
import { RootState, store } from "../../../../state/store.ts";
import { RootState } from "../../../../state/store.ts";
import { useVideoPlayerState } from "../VideoPlayer-State.ts";
import { VideoPlayerProps } from "../VideoPlayer.tsx";
@ -38,6 +30,7 @@ export const useVideoControlsState = (
progress,
videoObjectFit,
canPlay,
containerRef,
} = videoPlayerState;
const { identifier, autoPlay } = props;
@ -78,16 +71,15 @@ export const useVideoControlsState = (
const isFullscreen = useSignal(false);
const enterFullscreen = () => {
if (!videoRef.current) return;
if (videoRef.current.requestFullscreen) {
videoRef.current.requestFullscreen();
if (!containerRef.current) return;
if (containerRef.current.requestFullscreen && !isFullscreen.value) {
containerRef.current.requestFullscreen();
}
};
const exitFullscreen = () => {
if (document.exitFullscreen) {
document.exitFullscreen();
}
if (isFullscreen.value) document.exitFullscreen();
};
const toggleFullscreen = () => {
@ -218,14 +210,20 @@ export const useVideoControlsState = (
}
};
const toggleStretchVideoSetting = () => {
const newStretchVideoSetting =
persistSelector.stretchVideoSetting === "contain" ? "fill" : "contain";
videoObjectFit.value = newStretchVideoSetting;
const setStretchVideoSetting = (value: "contain" | "fill") => {
videoObjectFit.value = value;
};
const keyboardShortcutsDown = (e: React.KeyboardEvent<HTMLDivElement>) => {
const toggleStretchVideoSetting = () => {
videoObjectFit.value =
videoObjectFit.value === "contain" ? "fill" : "contain";
};
const keyboardShortcuts = (
e: KeyboardEvent | React.KeyboardEvent<HTMLDivElement>
) => {
e.preventDefault();
// console.log("hotkey is: ", '"' + e.key + '"');
switch (e.key) {
case "o":
@ -276,13 +274,6 @@ export const useVideoControlsState = (
case Key.ArrowUp:
changeVolume(0.05);
break;
}
};
const keyboardShortcutsUp = (e: React.KeyboardEvent<HTMLDivElement>) => {
e.preventDefault();
switch (e.key) {
case " ":
togglePlay();
break;
@ -291,12 +282,20 @@ export const useVideoControlsState = (
break;
case "f":
enterFullscreen();
toggleFullscreen();
break;
case Key.Escape:
exitFullscreen();
break;
case "r":
reloadVideo();
break;
case "p":
togglePictureInPicture();
break;
case "0":
setProgressAbsolute(0);
break;
@ -360,11 +359,12 @@ export const useVideoControlsState = (
increaseSpeed,
togglePictureInPicture,
toggleFullscreen,
keyboardShortcutsUp,
keyboardShortcutsDown,
keyboardShortcuts,
handleCanPlay,
toggleMute,
showControlsFullScreen,
setPlaying,
isFullscreen,
setStretchVideoSetting,
};
};

View File

@ -1,3 +1,8 @@
import { IconButton, Slider, Typography } from "@mui/material";
import { fontSizeExSmall, fontSizeSmall } from "../../../../constants/Misc.ts";
import { CustomFontTooltip } from "../../../../utils/CustomFontTooltip.tsx";
import { formatTime } from "../../../../utils/numberFunctions.ts";
import { useVideoContext } from "./VideoContext.ts";
import {
Fullscreen,
Pause,
@ -7,142 +12,190 @@ import {
VolumeOff,
VolumeUp,
} from "@mui/icons-material";
import { IconButton, Slider, Typography, useMediaQuery } from "@mui/material";
import { smallScreenSizeString } from "../../../../constants/Misc.ts";
import { formatTime } from "../../../../utils/numberFunctions.ts";
import { ControlsContainer } from "../VideoPlayer-styles.ts";
import { MobileControls } from "./MobileControls.tsx";
import { useVideoContext } from "./VideoContext.ts";
import { useSignalEffect } from "@preact/signals-react";
export const VideoControls = () => {
const {
reloadVideo,
togglePlay,
onVolumeChange,
increaseSpeed,
togglePictureInPicture,
toggleFullscreen,
toggleMute,
onProgressChange,
toggleRef,
from,
videoRef,
canPlay,
isMuted,
playbackRate,
playing,
progress,
volume,
showControlsFullScreen,
} = useVideoContext();
export const PlayButton = () => {
const { togglePlay, playing } = useVideoContext();
return (
<CustomFontTooltip title="Pause/Play (Spacebar)" placement="top" arrow>
<IconButton
sx={{
color: "white",
}}
onClick={() => togglePlay()}
>
{playing.value ? <Pause /> : <PlayArrow />}
</IconButton>
</CustomFontTooltip>
);
};
const isScreenSmall = !useMediaQuery(`(min-width:580px)`);
const showMobileControls = isScreenSmall && canPlay.value;
export const ReloadButton = () => {
const { reloadVideo } = useVideoContext();
return (
<CustomFontTooltip title="Reload Video (R)" placement="top" arrow>
<IconButton
sx={{
color: "white",
}}
onClick={reloadVideo}
>
<Refresh />
</IconButton>
</CustomFontTooltip>
);
};
export const ProgressSlider = () => {
const { progress, onProgressChange, videoRef } = useVideoContext();
const sliderThumbSize = "16px";
return (
<Slider
value={progress.value}
onChange={onProgressChange}
min={0}
max={videoRef.current?.duration || 100}
sx={{
position: "absolute",
bottom: "40px",
color: "#00abff",
padding: "0px",
// prevents the slider from jumping up 20px in certain mobile conditions
"@media (pointer: coarse)": { padding: "0px" },
"& .MuiSlider-thumb": {
backgroundColor: "#fff",
width: sliderThumbSize,
height: sliderThumbSize,
},
"& .MuiSlider-rail": { opacity: 0.5 },
}}
/>
);
};
export const VideoTime = () => {
const { videoRef, progress, isScreenSmall } = useVideoContext();
return (
<ControlsContainer
style={{ bottom: from === "create" ? "15px" : 0, padding: "0px" }}
display={showControlsFullScreen.value ? "flex" : "none"}
<CustomFontTooltip
title="Seek video in 10% increments (0-9)"
placement="top"
arrow
>
{showMobileControls ? (
<MobileControls />
) : canPlay.value ? (
<>
<IconButton
sx={{
color: "rgba(255, 255, 255, 0.7)",
}}
onClick={() => togglePlay()}
>
{playing.value ? <Pause /> : <PlayArrow />}
</IconButton>
<IconButton
sx={{
color: "rgba(255, 255, 255, 0.7)",
marginLeft: "15px",
}}
onClick={reloadVideo}
>
<Refresh />
</IconButton>
<Slider
value={progress.value}
onChange={onProgressChange}
min={0}
max={videoRef.current?.duration || 100}
sx={{ flexGrow: 1, mx: 2 }}
/>
<Typography
sx={{
fontSize: "14px",
marginRight: "5px",
color: "rgba(255, 255, 255, 0.7)",
visibility:
!videoRef.current?.duration || !progress.value
? "hidden"
: "visible",
}}
>
{progress.value &&
videoRef.current?.duration &&
formatTime(progress.value)}
/
{progress.value &&
videoRef.current?.duration &&
formatTime(videoRef.current?.duration)}
</Typography>
<IconButton
sx={{
color: "rgba(255, 255, 255, 0.7)",
marginRight: "10px",
}}
onClick={toggleMute}
>
{isMuted.value ? <VolumeOff /> : <VolumeUp />}
</IconButton>
<Slider
value={volume.value}
onChange={onVolumeChange}
min={0}
max={1}
step={0.01}
sx={{
maxWidth: "100px",
}}
/>
<IconButton
sx={{
color: "rgba(255, 255, 255, 0.7)",
fontSize: "14px",
marginLeft: "5px",
}}
onClick={e => increaseSpeed()}
>
Speed: {playbackRate}x
</IconButton>
<Typography
sx={{
fontSize: isScreenSmall ? fontSizeExSmall : fontSizeSmall,
color: "white",
visibility: !videoRef.current?.duration ? "hidden" : "visible",
whiteSpace: "nowrap",
}}
>
{videoRef.current?.duration ? formatTime(progress.value) : ""}
{" / "}
{videoRef.current?.duration
? formatTime(videoRef.current?.duration)
: ""}
</Typography>
</CustomFontTooltip>
);
};
export const VolumeButton = () => {
const { isMuted, toggleMute } = useVideoContext();
return (
<CustomFontTooltip
title="Toggle Mute (M), Raise (UP), Lower (DOWN)"
placement="top"
arrow
>
<IconButton
sx={{
color: "white",
}}
onClick={toggleMute}
>
{isMuted.value ? <VolumeOff /> : <VolumeUp />}
</IconButton>
</CustomFontTooltip>
);
};
export const VolumeSlider = () => {
const { volume, onVolumeChange } = useVideoContext();
return (
<Slider
value={volume.value}
onChange={onVolumeChange}
min={0}
max={1}
step={0.01}
sx={{
width: "100px",
}}
/>
);
};
export const PlaybackRate = () => {
const { playbackRate, increaseSpeed, isScreenSmall } = useVideoContext();
return (
<CustomFontTooltip
title="Video Speed. Increase (+ or >), Decrease (- or <)"
placement="top"
arrow
>
<IconButton
sx={{
color: "white",
fontSize: isScreenSmall ? fontSizeExSmall : fontSizeSmall,
paddingTop: "0px",
paddingBottom: "0px",
}}
onClick={() => increaseSpeed()}
>
<span style={{ display: "flex", alignItems: "center", height: "40px" }}>
{playbackRate}x
</span>
</IconButton>
</CustomFontTooltip>
);
};
export const PictureInPictureButton = () => {
const { isFullscreen, toggleRef, togglePictureInPicture } = useVideoContext();
return (
<>
{!isFullscreen.value && (
<CustomFontTooltip title="Picture in Picture (P)" placement="top" arrow>
<IconButton
sx={{
color: "rgba(255, 255, 255, 0.7)",
marginLeft: "15px",
color: "white",
}}
ref={toggleRef}
onClick={togglePictureInPicture}
>
<PictureInPicture />
</IconButton>
<IconButton
sx={{
color: "rgba(255, 255, 255, 0.7)",
}}
onClick={toggleFullscreen}
>
<Fullscreen />
</IconButton>
</>
) : null}
</ControlsContainer>
</CustomFontTooltip>
)}
</>
);
};
export const FullscreenButton = () => {
const { toggleFullscreen } = useVideoContext();
return (
<CustomFontTooltip title="Toggle Fullscreen (F)" placement="top" arrow>
<IconButton
sx={{
color: "white",
paddingRight: "0px",
}}
onClick={() => toggleFullscreen()}
>
<Fullscreen />
</IconButton>
</CustomFontTooltip>
);
};

View File

@ -0,0 +1,62 @@
import { Box } from "@mui/material";
import { ControlsContainer } from "../VideoPlayer-styles.ts";
import { MobileControlsBar } from "./MobileControlsBar.tsx";
import { useVideoContext } from "./VideoContext.ts";
import {
FullscreenButton,
PictureInPictureButton,
PlaybackRate,
PlayButton,
ProgressSlider,
ReloadButton,
VideoTime,
VolumeButton,
VolumeSlider,
} from "./VideoControls.tsx";
import { useSignalEffect } from "@preact/signals-react";
export const VideoControlsBar = () => {
const { from, canPlay, showControlsFullScreen, isScreenSmall, progress } =
useVideoContext();
const showMobileControls = isScreenSmall && canPlay.value;
const controlsHeight = "40px";
const controlGroupSX = {
display: "flex",
gap: "5px",
alignItems: "center",
height: controlsHeight,
};
return (
<ControlsContainer
style={{
padding: "0px",
height: controlsHeight,
}}
>
{showMobileControls ? (
<MobileControlsBar />
) : canPlay.value ? (
<>
<Box sx={controlGroupSX}>
<PlayButton />
<ReloadButton />
<ProgressSlider />
<VolumeButton />
<VolumeSlider />
<VideoTime />
</Box>
<Box sx={controlGroupSX}>
<PlaybackRate />
<PictureInPictureButton />
<FullscreenButton />
</Box>
</>
) : null}
</ControlsContainer>
);
};

View File

@ -1,3 +1,4 @@
import { useMediaQuery } from "@mui/material";
import {
useSignal,
useSignalEffect,
@ -12,6 +13,7 @@ import React, {
} from "react";
import { useDispatch, useSelector } from "react-redux";
import { smallVideoSize } from "../../../constants/Misc.ts";
import { setVideoPlaying } from "../../../state/features/globalSlice.ts";
import {
setIsMuted,
@ -292,6 +294,7 @@ export const useVideoPlayerState = (props: VideoPlayerProps, ref: any) => {
anchorEl.value = null;
};
const isScreenSmall = !useMediaQuery(smallVideoSize);
return {
containerRef,
resourceStatus,
@ -315,5 +318,6 @@ export const useVideoPlayerState = (props: VideoPlayerProps, ref: any) => {
playbackRate,
anchorEl,
videoObjectFit,
isScreenSmall,
};
};

View File

@ -20,12 +20,9 @@ export const VideoElement = styled("video")(({ theme }) => ({
}));
//1075 x 604
export const ControlsContainer = styled(Box)`
position: absolute;
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
bottom: 0;
left: 0;
right: 0;
background-color: rgba(0, 0, 0, 0.6);
`;

View File

@ -1,8 +1,9 @@
import CSS from "csstype";
import { forwardRef } from "react";
import useIdleTimeout from "../../../hooks/useIdleTimeout.ts";
import { LoadingVideo } from "./Components/LoadingVideo.tsx";
import { useContextData, VideoContext } from "./Components/VideoContext.ts";
import { VideoControls } from "./Components/VideoControls.tsx";
import { VideoControlsBar } from "./Components/VideoControlsBar.tsx";
import { VideoContainer, VideoElement } from "./VideoPlayer-styles.ts";
export interface VideoStyles {
@ -37,8 +38,7 @@ export const VideoPlayer = forwardRef<videoRefType, VideoPlayerProps>(
const contextData = useContextData(props, ref);
const {
keyboardShortcutsUp,
keyboardShortcutsDown,
keyboardShortcuts,
from,
videoStyles,
containerRef,
@ -55,18 +55,35 @@ export const VideoPlayer = forwardRef<videoRefType, VideoPlayerProps>(
startPlay,
videoObjectFit,
showControlsFullScreen,
isFullscreen,
} = contextData;
const showControls =
!isFullscreen.value ||
(isFullscreen.value && showControlsFullScreen.value);
const idleTime = 5000; // Time in milliseconds
useIdleTimeout({
onIdle: () => (showControlsFullScreen.value = false),
onActive: () => (showControlsFullScreen.value = true),
idleTime,
});
return (
<VideoContext.Provider value={contextData}>
<VideoContainer
tabIndex={0}
onKeyUp={keyboardShortcutsUp}
onKeyDown={keyboardShortcutsDown}
onKeyDown={keyboardShortcuts}
style={{
padding: from === "create" ? "8px" : 0,
...videoStyles?.videoContainer,
}}
onMouseEnter={e => {
showControlsFullScreen.value = true;
}}
onMouseLeave={e => {
showControlsFullScreen.value = false;
}}
ref={containerRef}
>
<LoadingVideo />
@ -83,23 +100,17 @@ export const VideoPlayer = forwardRef<videoRefType, VideoPlayerProps>(
onEnded={handleEnded}
// onLoadedMetadata={handleLoadedMetadata}
onCanPlay={handleCanPlay}
onMouseEnter={e => {
showControlsFullScreen.value = true;
}}
onMouseLeave={e => {
showControlsFullScreen.value = false;
}}
preload="metadata"
style={
startPlay.value
? {
...videoStyles?.video,
objectFit: videoObjectFit.value,
}
: { height: "100%", ...videoStyles }
}
style={{
...videoStyles?.video,
objectFit: isFullscreen ? "fill" : videoObjectFit.value,
height:
isFullscreen.value && showControlsFullScreen.value
? "calc(100vh - 40px)"
: "100%",
}}
/>
<VideoControls />
{showControls && <VideoControlsBar />}
</VideoContainer>
</VideoContext.Provider>
);

View File

@ -21,5 +21,6 @@ const largeScreenSize = 1400 - newUIWidthDiff;
export const smallScreenSizeString = `${smallScreenSize}px`;
export const largeScreenSizeString = `${largeScreenSize}px`;
export const smallVideoSize = `(min-width:720px)`;
export const headerIconSize = "40px";
export const menuIconSize = "28px";

View File

@ -0,0 +1,14 @@
import { useContext, useState } from "react";
import { useIdleTimer } from "react-idle-timer";
const useIdleTimeout = ({ onIdle, onActive, idleTime = 10_000 }) => {
const idleTimer = useIdleTimer({
timeout: idleTime,
onIdle: onIdle,
onActive: onActive,
});
return {
idleTimer,
};
};
export default useIdleTimeout;

View File

@ -11,6 +11,7 @@ import {
largeScreenSizeString,
minFileSize,
smallScreenSizeString,
smallVideoSize,
} from "../../../constants/Misc.ts";
import { useIsMobile } from "../../../hooks/useIsMobile.ts";
import { formatBytes } from "../../../utils/numberFunctions.ts";
@ -47,7 +48,7 @@ export const VideoContent = () => {
setSuperLikeList,
} = useVideoContentState();
const isScreenSmall = !useMediaQuery(`(min-width:${smallScreenSizeString})`);
const isScreenSmall = !useMediaQuery(smallVideoSize);
const [screenWidth, setScreenWidth] = useState<number>(
window.innerWidth + 120
);
@ -75,7 +76,7 @@ export const VideoContent = () => {
sx={{
display: "flex",
flexDirection: "column",
padding: `0px 0px 0px ${isScreenSmall ? "5px" : "2%"}`,
padding: `0px 0px 0px ${isScreenSmall ? "0px" : "2%"}`,
width: "100%",
}}
onClick={focusVideo}
@ -112,7 +113,9 @@ export const VideoContent = () => {
) : (
<Box sx={{ width: "55vw", aspectRatio: "16/9" }}></Box>
)}
<VideoContentContainer>
<VideoContentContainer
sx={{ paddingLeft: isScreenSmall ? "5px" : "0px" }}
>
<VideoTitle
variant={isScreenSmall ? "h2" : "h1"}
color="textPrimary"

View File

@ -1,20 +1,13 @@
import { TabContext, TabList, TabPanel } from "@mui/lab";
import { Box, Grid, Tab, useMediaQuery } from "@mui/material";
import { Box, Tab, useMediaQuery } from "@mui/material";
import React from "react";
import LazyLoad from "../../components/common/LazyLoad";
import { ListSuperLikeContainer } from "../../components/common/ListSuperLikes/ListSuperLikeContainer.tsx";
import {
fontSizeLarge,
fontSizeMedium,
fontSizeSmall,
} from "../../constants/Misc.ts";
import { useIsMobile } from "../../hooks/useIsMobile.ts";
import { fontSizeLarge, fontSizeSmall } from "../../constants/Misc.ts";
import { SearchSidebar } from "./Components/SearchSidebar.tsx";
import { FiltersCol, VideoManagerRow } from "./Components/VideoList-styles.tsx";
import VideoList from "./Components/VideoList.tsx";
import { useHomeState } from "./Home-State.ts";
import { SubtitleContainer } from "./Home-styles";
interface HomeProps {
mode?: string;

View File

@ -0,0 +1,23 @@
import { Box, Tooltip, TooltipProps } from "@mui/material";
import { PropsWithChildren } from "react";
import { fontSizeSmall } from "../constants/Misc";
export interface CustomFontTooltipProps extends TooltipProps {
fontSize?: string;
}
export const CustomFontTooltip = ({
fontSize,
title,
children,
...props
}: PropsWithChildren<CustomFontTooltipProps>) => {
if (!fontSize) fontSize = "160%";
const text = <Box sx={{ fontSize: fontSize }}>{title}</Box>;
// put controls into individual components
return (
<Tooltip title={text} {...props} sx={{ display: "contents", ...props.sx }}>
<div>{children}</div>
</Tooltip>
);
};

View File

@ -1,8 +1,9 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
base: ""
})
server: { port: 3000 },
base: "",
});