style: Improve touch screen compatibility

This commit is contained in:
Peifan Li
2025-12-20 22:55:11 -05:00
parent bfc2fe8cfe
commit 9823e63db2
9 changed files with 47 additions and 36 deletions

View File

@@ -33,6 +33,7 @@ const ActionButtons: React.FC<ActionButtonsProps> = ({
const { visitorMode } = useVisitorMode();
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
const isTouch = useMediaQuery('(hover: none), (pointer: coarse)');
return (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
@@ -57,7 +58,7 @@ const ActionButtons: React.FC<ActionButtonsProps> = ({
</IconButton>
{!isMobile && (
<Tooltip title={t('manage')}>
<Tooltip title={t('manage')} disableHoverListener={isTouch}>
<IconButton
color="inherit"
onClick={onManageClick}

View File

@@ -12,7 +12,8 @@ import {
TableHead,
TableRow,
Tooltip,
Typography
Typography,
useMediaQuery
} from '@mui/material';
import React from 'react';
import { useLanguage } from '../../contexts/LanguageContext';
@@ -40,6 +41,7 @@ const CollectionsTable: React.FC<CollectionsTableProps> = ({
}) => {
const { t } = useLanguage();
const { visitorMode } = useVisitorMode();
const isTouch = useMediaQuery('(hover: none), (pointer: coarse)');
return (
<Box sx={{ mb: 6 }}>
@@ -71,7 +73,7 @@ const CollectionsTable: React.FC<CollectionsTableProps> = ({
<TableCell>{new Date(collection.createdAt).toLocaleDateString()}</TableCell>
{!visitorMode && (
<TableCell align="right">
<Tooltip title={t('deleteCollection')}>
<Tooltip title={t('deleteCollection')} disableHoverListener={isTouch}>
<IconButton
color="error"
onClick={() => onDelete(collection)}

View File

@@ -24,7 +24,8 @@ import {
TableSortLabel,
TextField,
Tooltip,
Typography
Typography,
useMediaQuery
} from '@mui/material';
import React, { useState } from 'react';
import { Link } from 'react-router-dom';
@@ -96,6 +97,7 @@ const VideosTable: React.FC<VideosTableProps> = ({
}) => {
const { t } = useLanguage();
const { visitorMode } = useVisitorMode();
const isTouch = useMediaQuery('(hover: none), (pointer: coarse)');
// Local editing state
const [editingVideoId, setEditingVideoId] = useState<string | null>(null);
@@ -194,7 +196,7 @@ const VideosTable: React.FC<VideosTableProps> = ({
<ThumbnailImage video={video} />
</Link>
{!visitorMode && (
<Tooltip title={t('refreshThumbnail') || "Refresh Thumbnail"}>
<Tooltip title={t('refreshThumbnail') || "Refresh Thumbnail"} disableHoverListener={isTouch}>
<IconButton
size="small"
onClick={() => onRefreshThumbnail(video.id)}
@@ -296,7 +298,7 @@ const VideosTable: React.FC<VideosTableProps> = ({
<TableCell>{formatSize(video.fileSize)}</TableCell>
{!visitorMode && (
<TableCell align="right">
<Tooltip title={t('deleteVideo')}>
<Tooltip title={t('deleteVideo')} disableHoverListener={isTouch}>
<IconButton
color="error"
onClick={() => onDeleteClick(video.id)}

View File

@@ -161,7 +161,7 @@ const UpNextSidebar: React.FC<UpNextSidebarProps> = ({
</Box>
{hoveredVideoId === relatedVideo.id && !isMobile && !isTouch && !visitorMode && (
<Tooltip title={t('addToCollection')}>
<Tooltip title={t('addToCollection')} disableHoverListener={isTouch}>
<IconButton
size="small"
onClick={(e) => handleAddToCollectionClick(e, relatedVideo.id)}

View File

@@ -25,6 +25,7 @@ import {
Stack,
Tooltip,
Typography,
useMediaQuery,
useTheme
} from '@mui/material';
import React, { useEffect, useRef, useState } from 'react';
@@ -59,6 +60,7 @@ const VideoControls: React.FC<VideoControlsProps> = ({
}) => {
const theme = useTheme();
const { t } = useLanguage();
const isTouch = useMediaQuery('(hover: none), (pointer: coarse)');
const videoRef = useRef<HTMLVideoElement>(null);
const [isPlaying, setIsPlaying] = useState<boolean>(false);
@@ -593,7 +595,7 @@ const VideoControls: React.FC<VideoControlsProps> = ({
}, 200);
}}
>
<Tooltip title={volume === 0 ? 'Unmute' : 'Mute'}>
<Tooltip title={volume === 0 ? 'Unmute' : 'Mute'} disableHoverListener={isTouch}>
<IconButton
onClick={handleVolumeClick}
size="small"
@@ -656,7 +658,7 @@ const VideoControls: React.FC<VideoControlsProps> = ({
</Box>
{/* Play/Pause */}
<Tooltip title={isPlaying ? t('paused') : t('playing')}>
<Tooltip title={isPlaying ? t('paused') : t('playing')} disableHoverListener={isTouch}>
<IconButton
color={isPlaying ? "secondary" : "primary"}
onClick={handlePlayPause}
@@ -715,7 +717,7 @@ const VideoControls: React.FC<VideoControlsProps> = ({
{/* Subtitle Button (Mobile only, next to progress bar) */}
{subtitles && subtitles.length > 0 && (
<>
<Tooltip title={subtitlesEnabled ? 'Subtitles' : 'Subtitles Off'}>
<Tooltip title={subtitlesEnabled ? 'Subtitles' : 'Subtitles Off'} disableHoverListener={isTouch}>
<IconButton
color={subtitlesEnabled ? "primary" : "default"}
onClick={handleSubtitleClick}
@@ -731,7 +733,7 @@ const VideoControls: React.FC<VideoControlsProps> = ({
{/* Right Side: Fullscreen, Subtitle, Loop (Desktop only) */}
<Stack direction="row" spacing={0.5} alignItems="center" sx={{ ml: 1, display: { xs: 'none', sm: 'flex' } }}>
{/* Fullscreen */}
<Tooltip title={isFullscreen ? t('exitFullscreen') : t('enterFullscreen')}>
<Tooltip title={isFullscreen ? t('exitFullscreen') : t('enterFullscreen')} disableHoverListener={isTouch}>
<IconButton
onClick={handleToggleFullscreen}
size="small"
@@ -743,7 +745,7 @@ const VideoControls: React.FC<VideoControlsProps> = ({
{/* Subtitle */}
{subtitles && subtitles.length > 0 && (
<>
<Tooltip title={subtitlesEnabled ? 'Subtitles' : 'Subtitles Off'}>
<Tooltip title={subtitlesEnabled ? 'Subtitles' : 'Subtitles Off'} disableHoverListener={isTouch}>
<IconButton
color={subtitlesEnabled ? "primary" : "default"}
onClick={handleSubtitleClick}
@@ -770,7 +772,7 @@ const VideoControls: React.FC<VideoControlsProps> = ({
)}
{/* Loop */}
<Tooltip title={`${t('loop')} ${isLooping ? t('on') : t('off')}`}>
<Tooltip title={`${t('loop')} ${isLooping ? t('on') : t('off')}`} disableHoverListener={isTouch}>
<IconButton
color={isLooping ? "primary" : "default"}
onClick={handleToggleLoop}
@@ -791,7 +793,7 @@ const VideoControls: React.FC<VideoControlsProps> = ({
alignItems="center"
sx={{ width: '100%', flexWrap: 'wrap' }}
>
<Tooltip title="-10m">
<Tooltip title="-10m" disableHoverListener={isTouch}>
<IconButton
onClick={() => handleSeek(-600)}
size="small"
@@ -800,7 +802,7 @@ const VideoControls: React.FC<VideoControlsProps> = ({
<KeyboardDoubleArrowLeft />
</IconButton>
</Tooltip>
<Tooltip title="-1m">
<Tooltip title="-1m" disableHoverListener={isTouch}>
<IconButton
onClick={() => handleSeek(-60)}
size="small"
@@ -809,7 +811,7 @@ const VideoControls: React.FC<VideoControlsProps> = ({
<FastRewind />
</IconButton>
</Tooltip>
<Tooltip title="-10s">
<Tooltip title="-10s" disableHoverListener={isTouch}>
<IconButton
onClick={() => handleSeek(-10)}
size="small"
@@ -818,7 +820,7 @@ const VideoControls: React.FC<VideoControlsProps> = ({
<Replay10 />
</IconButton>
</Tooltip>
<Tooltip title="+10s">
<Tooltip title="+10s" disableHoverListener={isTouch}>
<IconButton
onClick={() => handleSeek(10)}
size="small"
@@ -827,7 +829,7 @@ const VideoControls: React.FC<VideoControlsProps> = ({
<Forward10 />
</IconButton>
</Tooltip>
<Tooltip title="+1m">
<Tooltip title="+1m" disableHoverListener={isTouch}>
<IconButton
onClick={() => handleSeek(60)}
size="small"
@@ -836,7 +838,7 @@ const VideoControls: React.FC<VideoControlsProps> = ({
<FastForward />
</IconButton>
</Tooltip>
<Tooltip title="+10m">
<Tooltip title="+10m" disableHoverListener={isTouch}>
<IconButton
onClick={() => handleSeek(600)}
size="small"
@@ -849,7 +851,7 @@ const VideoControls: React.FC<VideoControlsProps> = ({
{/* Mobile: Fullscreen, Loop */}
<Stack direction="row" spacing={0.5} alignItems="center" sx={{ display: { xs: 'flex', sm: 'none' }, ml: 1 }}>
{/* Fullscreen */}
<Tooltip title={isFullscreen ? t('exitFullscreen') : t('enterFullscreen')}>
<Tooltip title={isFullscreen ? t('exitFullscreen') : t('enterFullscreen')} disableHoverListener={isTouch}>
<IconButton
onClick={handleToggleFullscreen}
size="small"
@@ -859,7 +861,7 @@ const VideoControls: React.FC<VideoControlsProps> = ({
</Tooltip>
{/* Loop */}
<Tooltip title={`${t('loop')} ${isLooping ? t('on') : t('off')}`}>
<Tooltip title={`${t('loop')} ${isLooping ? t('on') : t('off')}`} disableHoverListener={isTouch}>
<IconButton
color={isLooping ? "primary" : "default"}
onClick={handleToggleLoop}

View File

@@ -1,5 +1,5 @@
import { Check, Close, Edit, ExpandLess, ExpandMore } from '@mui/icons-material';
import { Box, Button, TextField, Tooltip, Typography } from '@mui/material';
import { Box, Button, TextField, Tooltip, Typography, useMediaQuery } from '@mui/material';
import React, { useEffect, useRef, useState } from 'react';
import { useLanguage } from '../../../contexts/LanguageContext';
import { useVisitorMode } from '../../../contexts/VisitorModeContext';
@@ -12,6 +12,7 @@ interface EditableTitleProps {
const EditableTitle: React.FC<EditableTitleProps> = ({ title, onSave }) => {
const { t } = useLanguage();
const { visitorMode } = useVisitorMode();
const isTouch = useMediaQuery('(hover: none), (pointer: coarse)');
const [isEditingTitle, setIsEditingTitle] = useState<boolean>(false);
const [editedTitle, setEditedTitle] = useState<string>('');
const [isTitleExpanded, setIsTitleExpanded] = useState(false);
@@ -106,7 +107,7 @@ const EditableTitle: React.FC<EditableTitleProps> = ({ title, onSave }) => {
</Typography>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.5 }}>
{!visitorMode && (
<Tooltip title={t('editTitle')}>
<Tooltip title={t('editTitle')} disableHoverListener={isTouch}>
<Button
size="small"
onClick={handleStartEditingTitle}
@@ -117,7 +118,7 @@ const EditableTitle: React.FC<EditableTitleProps> = ({ title, onSave }) => {
</Tooltip>
)}
{showExpandButton && (
<Tooltip title={isTitleExpanded ? t('collapse') : t('expand')}>
<Tooltip title={isTitleExpanded ? t('collapse') : t('expand')} disableHoverListener={isTouch}>
<Button
size="small"
onClick={() => setIsTitleExpanded(!isTitleExpanded)}

View File

@@ -28,6 +28,7 @@ const VideoActionButtons: React.FC<VideoActionButtonsProps> = ({
const { visitorMode } = useVisitorMode();
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
const isTouch = useMediaQuery('(hover: none), (pointer: coarse)');
const [playerMenuAnchor, setPlayerMenuAnchor] = useState<null | HTMLElement>(null);
const videoUrl = useCloudStorageUrl(video.videoPath, 'video');
@@ -138,7 +139,7 @@ const VideoActionButtons: React.FC<VideoActionButtonsProps> = ({
const actionButtons = (
<Stack direction="row" spacing={1}>
<Tooltip title={t('playWith')}>
<Tooltip title={t('playWith')} disableHoverListener={isTouch}>
<Button
variant="outlined"
color="inherit"
@@ -169,7 +170,7 @@ const VideoActionButtons: React.FC<VideoActionButtonsProps> = ({
<MenuItem onClick={() => handlePlayerSelect('copy')}>{t('copyUrl')}</MenuItem>
</Menu>
<Tooltip title={t('share')}>
<Tooltip title={t('share')} disableHoverListener={isTouch}>
<Button
variant="outlined"
color="inherit"
@@ -181,7 +182,7 @@ const VideoActionButtons: React.FC<VideoActionButtonsProps> = ({
</Tooltip>
{!visitorMode && (
<>
<Tooltip title={t('addToCollection')}>
<Tooltip title={t('addToCollection')} disableHoverListener={isTouch}>
<Button
variant="outlined"
color="inherit"
@@ -191,7 +192,7 @@ const VideoActionButtons: React.FC<VideoActionButtonsProps> = ({
<Add />
</Button>
</Tooltip>
<Tooltip title={t('delete')}>
<Tooltip title={t('delete')} disableHoverListener={isTouch}>
<Button
variant="outlined"
color="inherit"

View File

@@ -1,5 +1,5 @@
import { Notifications, NotificationsActive } from '@mui/icons-material';
import { Avatar, Box, IconButton, Tooltip, Typography } from '@mui/material';
import { Avatar, Box, IconButton, Tooltip, Typography, useMediaQuery } from '@mui/material';
import React from 'react';
import { useLanguage } from '../../../contexts/LanguageContext';
import { useVisitorMode } from '../../../contexts/VisitorModeContext';
@@ -38,6 +38,7 @@ const VideoAuthorInfo: React.FC<VideoAuthorInfoProps> = ({
}) => {
const { t } = useLanguage();
const { visitorMode } = useVisitorMode();
const isTouch = useMediaQuery('(hover: none), (pointer: coarse)');
const showSubscribeButton = (source === 'youtube' || source === 'bilibili') && !visitorMode;
const handleSubscribeClick = (e: React.MouseEvent) => {
@@ -83,7 +84,7 @@ const VideoAuthorInfo: React.FC<VideoAuthorInfoProps> = ({
</Typography>
</Box>
{showSubscribeButton && (
<Tooltip title={isSubscribed ? t('unsubscribe') : t('subscribe')}>
<Tooltip title={isSubscribed ? t('unsubscribe') : t('subscribe')} disableHoverListener={isTouch}>
<IconButton
size="small"
onClick={handleSubscribeClick}

View File

@@ -1,5 +1,5 @@
import { Add, Cast, Delete, MoreVert, Share } from '@mui/icons-material';
import { Button, IconButton, Menu, Stack, Tooltip } from '@mui/material';
import { Button, IconButton, Menu, Stack, Tooltip, useMediaQuery } from '@mui/material';
import React, { useState } from 'react';
import { useLanguage } from '../../../contexts/LanguageContext';
import { useVisitorMode } from '../../../contexts/VisitorModeContext';
@@ -23,6 +23,7 @@ const VideoKebabMenuButtons: React.FC<VideoKebabMenuButtonsProps> = ({
}) => {
const { t } = useLanguage();
const { visitorMode } = useVisitorMode();
const isTouch = useMediaQuery('(hover: none), (pointer: coarse)');
const [kebabMenuAnchor, setKebabMenuAnchor] = useState<null | HTMLElement>(null);
const handleKebabMenuOpen = (event: React.MouseEvent<HTMLElement>) => {
@@ -73,7 +74,7 @@ const VideoKebabMenuButtons: React.FC<VideoKebabMenuButtonsProps> = ({
return (
<>
<Tooltip title="More actions">
<Tooltip title="More actions" disableHoverListener={isTouch}>
<IconButton
onClick={handleKebabMenuOpen}
sx={{
@@ -110,7 +111,7 @@ const VideoKebabMenuButtons: React.FC<VideoKebabMenuButtonsProps> = ({
}}
>
<Stack direction="row" spacing={2} sx={{ justifyContent: 'flex-end' }}>
<Tooltip title={t('playWith')}>
<Tooltip title={t('playWith')} disableHoverListener={isTouch}>
<Button
variant="outlined"
color="inherit"
@@ -120,7 +121,7 @@ const VideoKebabMenuButtons: React.FC<VideoKebabMenuButtonsProps> = ({
<Cast />
</Button>
</Tooltip>
<Tooltip title={t('share')}>
<Tooltip title={t('share')} disableHoverListener={isTouch}>
<Button
variant="outlined"
color="inherit"
@@ -132,7 +133,7 @@ const VideoKebabMenuButtons: React.FC<VideoKebabMenuButtonsProps> = ({
</Tooltip>
{!visitorMode && (
<>
<Tooltip title={t('addToCollection')}>
<Tooltip title={t('addToCollection')} disableHoverListener={isTouch}>
<Button
variant="outlined"
color="inherit"
@@ -143,7 +144,7 @@ const VideoKebabMenuButtons: React.FC<VideoKebabMenuButtonsProps> = ({
</Button>
</Tooltip>
{onDelete && (
<Tooltip title={t('delete')}>
<Tooltip title={t('delete')} disableHoverListener={isTouch}>
<Button
variant="outlined"
color="inherit"