feat: Add VideoKebabMenuButtons component

This commit is contained in:
Peifan Li
2025-12-18 19:39:00 -05:00
parent dfd43107b4
commit cf5a48a6b6
2 changed files with 150 additions and 104 deletions

View File

@@ -1,10 +1,11 @@
import { Add, Cast, Delete, MoreVert, Share } from '@mui/icons-material';
import { Button, IconButton, Menu, MenuItem, Stack, Tooltip, useMediaQuery, useTheme } from '@mui/material';
import { Add, Cast, Delete, Share } from '@mui/icons-material';
import { Button, Menu, MenuItem, Stack, Tooltip, useMediaQuery, useTheme } from '@mui/material';
import React, { useState } from 'react';
import { useLanguage } from '../../../contexts/LanguageContext';
import { useSnackbar } from '../../../contexts/SnackbarContext';
import { useShareVideo } from '../../../hooks/useShareVideo';
import { Video } from '../../../types';
import VideoKebabMenuButtons from './VideoKebabMenuButtons';
interface VideoActionButtonsProps {
video: Video;
@@ -25,7 +26,6 @@ const VideoActionButtons: React.FC<VideoActionButtonsProps> = ({
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
const [playerMenuAnchor, setPlayerMenuAnchor] = useState<null | HTMLElement>(null);
const [kebabMenuAnchor, setKebabMenuAnchor] = useState<null | HTMLElement>(null);
const getVideoUrl = (): string => {
if (video.videoPath) {
@@ -47,13 +47,6 @@ const VideoActionButtons: React.FC<VideoActionButtonsProps> = ({
setPlayerMenuAnchor(null);
};
const handleKebabMenuOpen = (event: React.MouseEvent<HTMLElement>) => {
setKebabMenuAnchor(event.currentTarget);
};
const handleKebabMenuClose = () => {
setKebabMenuAnchor(null);
};
const handlePlayerSelect = (player: string) => {
const videoUrl = getVideoUrl();
@@ -203,100 +196,13 @@ const VideoActionButtons: React.FC<VideoActionButtonsProps> = ({
if (isMobile) {
return (
<>
<Tooltip title="More actions">
<IconButton
onClick={handleKebabMenuOpen}
sx={{
color: kebabMenuAnchor ? 'primary.main' : 'text.secondary',
'&:hover': { color: 'primary.main' }
}}
>
<MoreVert />
</IconButton>
</Tooltip>
<Menu
anchorEl={kebabMenuAnchor}
open={Boolean(kebabMenuAnchor)}
onClose={handleKebabMenuClose}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'right',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'right',
}}
slotProps={{
paper: {
sx: {
minWidth: 'auto',
p: 1,
px: 2,
}
}
}}
>
<Stack direction="row" spacing={2} sx={{ justifyContent: 'flex-end' }}>
<Tooltip title={t('playWith')}>
<Button
variant="outlined"
color="inherit"
onClick={() => {
// Store the anchor before closing the kebab menu
const anchor = kebabMenuAnchor;
handleKebabMenuClose();
// Use the stored anchor for the player menu
if (anchor) {
setPlayerMenuAnchor(anchor);
}
}}
sx={{ minWidth: 'auto', p: 1, color: 'text.secondary', borderColor: 'text.secondary', '&:hover': { color: 'primary.main', borderColor: 'primary.main' } }}
>
<Cast />
</Button>
</Tooltip>
<Tooltip title={t('share')}>
<Button
variant="outlined"
color="inherit"
onClick={() => {
handleKebabMenuClose();
handleShare();
}}
sx={{ minWidth: 'auto', p: 1, color: 'text.secondary', borderColor: 'text.secondary', '&:hover': { color: 'primary.main', borderColor: 'primary.main' } }}
>
<Share />
</Button>
</Tooltip>
<Tooltip title={t('addToCollection')}>
<Button
variant="outlined"
color="inherit"
onClick={() => {
handleKebabMenuClose();
onAddToCollection();
}}
sx={{ minWidth: 'auto', p: 1, color: 'text.secondary', borderColor: 'text.secondary', '&:hover': { color: 'primary.main', borderColor: 'primary.main' } }}
>
<Add />
</Button>
</Tooltip>
<Tooltip title={t('delete')}>
<Button
variant="outlined"
color="inherit"
onClick={() => {
handleKebabMenuClose();
onDelete();
}}
disabled={isDeleting}
sx={{ minWidth: 'auto', p: 1, color: 'text.secondary', borderColor: 'text.secondary', '&:hover': { color: 'error.main', borderColor: 'error.main' } }}
>
<Delete />
</Button>
</Tooltip>
</Stack>
</Menu>
<VideoKebabMenuButtons
onPlayWith={(anchor) => setPlayerMenuAnchor(anchor)}
onShare={handleShare}
onAddToCollection={onAddToCollection}
onDelete={onDelete}
isDeleting={isDeleting}
/>
<Menu
anchorEl={playerMenuAnchor}
open={Boolean(playerMenuAnchor)}

View File

@@ -0,0 +1,140 @@
import { Add, Cast, Delete, MoreVert, Share } from '@mui/icons-material';
import { Button, IconButton, Menu, Stack, Tooltip } from '@mui/material';
import React, { useState } from 'react';
import { useLanguage } from '../../../contexts/LanguageContext';
interface VideoKebabMenuButtonsProps {
onPlayWith: (anchor: HTMLElement) => void;
onShare: () => void;
onAddToCollection: () => void;
onDelete: () => void;
isDeleting?: boolean;
}
const VideoKebabMenuButtons: React.FC<VideoKebabMenuButtonsProps> = ({
onPlayWith,
onShare,
onAddToCollection,
onDelete,
isDeleting = false
}) => {
const { t } = useLanguage();
const [kebabMenuAnchor, setKebabMenuAnchor] = useState<null | HTMLElement>(null);
const handleKebabMenuOpen = (event: React.MouseEvent<HTMLElement>) => {
setKebabMenuAnchor(event.currentTarget);
};
const handleKebabMenuClose = () => {
setKebabMenuAnchor(null);
};
const handlePlayWith = () => {
const anchor = kebabMenuAnchor;
handleKebabMenuClose();
if (anchor) {
// Pass the anchor element to the parent so it can open the player menu at the same position
onPlayWith(anchor);
}
};
const handleShare = () => {
handleKebabMenuClose();
onShare();
};
const handleAddToCollection = () => {
handleKebabMenuClose();
onAddToCollection();
};
const handleDelete = () => {
handleKebabMenuClose();
onDelete();
};
return (
<>
<Tooltip title="More actions">
<IconButton
onClick={handleKebabMenuOpen}
sx={{
color: kebabMenuAnchor ? 'primary.main' : 'text.secondary',
'&:hover': { color: 'primary.main' }
}}
>
<MoreVert />
</IconButton>
</Tooltip>
<Menu
anchorEl={kebabMenuAnchor}
open={Boolean(kebabMenuAnchor)}
onClose={handleKebabMenuClose}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'right',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'right',
}}
slotProps={{
paper: {
sx: {
minWidth: 'auto',
p: 1,
px: 2,
}
}
}}
>
<Stack direction="row" spacing={2} sx={{ justifyContent: 'flex-end' }}>
<Tooltip title={t('playWith')}>
<Button
variant="outlined"
color="inherit"
onClick={handlePlayWith}
sx={{ minWidth: 'auto', p: 1, color: 'text.secondary', borderColor: 'text.secondary', '&:hover': { color: 'primary.main', borderColor: 'primary.main' } }}
>
<Cast />
</Button>
</Tooltip>
<Tooltip title={t('share')}>
<Button
variant="outlined"
color="inherit"
onClick={handleShare}
sx={{ minWidth: 'auto', p: 1, color: 'text.secondary', borderColor: 'text.secondary', '&:hover': { color: 'primary.main', borderColor: 'primary.main' } }}
>
<Share />
</Button>
</Tooltip>
<Tooltip title={t('addToCollection')}>
<Button
variant="outlined"
color="inherit"
onClick={handleAddToCollection}
sx={{ minWidth: 'auto', p: 1, color: 'text.secondary', borderColor: 'text.secondary', '&:hover': { color: 'primary.main', borderColor: 'primary.main' } }}
>
<Add />
</Button>
</Tooltip>
<Tooltip title={t('delete')}>
<Button
variant="outlined"
color="inherit"
onClick={handleDelete}
disabled={isDeleting}
sx={{ minWidth: 'auto', p: 1, color: 'text.secondary', borderColor: 'text.secondary', '&:hover': { color: 'error.main', borderColor: 'error.main' } }}
>
<Delete />
</Button>
</Tooltip>
</Stack>
</Menu>
</>
);
};
export default VideoKebabMenuButtons;