diff --git a/frontend/src/components/FloatingVideo.jsx b/frontend/src/components/FloatingVideo.jsx index d25f7468..ae66b08c 100644 --- a/frontend/src/components/FloatingVideo.jsx +++ b/frontend/src/components/FloatingVideo.jsx @@ -1,9 +1,9 @@ // frontend/src/components/FloatingVideo.js -import React, {useCallback, useEffect, useRef, useState} from 'react'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; import Draggable from 'react-draggable'; import useVideoStore from '../store/useVideoStore'; import mpegts from 'mpegts.js'; -import {Box, CloseButton, Flex, Loader, Text} from '@mantine/core'; +import { CloseButton, Flex, Loader, Text, Box } from '@mantine/core'; import { applyConstraints, calculateNewDimensions, @@ -644,15 +644,20 @@ export default function FloatingVideo() { }} > {/* Simple header row with a close button */} - + e.stopPropagation()} onTouchStart={(e) => e.stopPropagation()} - mih={32} - miw={32} style={{ + minHeight: '32px', + minWidth: '32px', cursor: 'pointer', touchAction: 'manipulation', }} @@ -661,7 +666,7 @@ export default function FloatingVideo() { {/* Video container with relative positioning for the overlay */} { if (contentType === 'vod' && !isLoading) { setShowOverlay(true); @@ -701,17 +706,17 @@ export default function FloatingVideo() { {/* VOD title overlay when not loading - auto-hides after 4 seconds */} {!isLoading && metadata && contentType === 'vod' && showOverlay && ( {metadata.year} @@ -736,14 +741,14 @@ export default function FloatingVideo() { {/* Loading overlay - only show when loading */} {isLoading && ( - + Loading {contentType === 'vod' ? 'video' : 'stream'}... @@ -761,13 +766,13 @@ export default function FloatingVideo() { {/* Error message below video - doesn't block controls */} {!isLoading && loadError && ( - + {loadError} diff --git a/frontend/src/components/M3URefreshNotification.jsx b/frontend/src/components/M3URefreshNotification.jsx index 5b40cadb..8fd461b4 100644 --- a/frontend/src/components/M3URefreshNotification.jsx +++ b/frontend/src/components/M3URefreshNotification.jsx @@ -57,12 +57,16 @@ export default function M3URefreshNotification() { const handleM3UUpdate = (data) => { // Skip if status hasn't changed - if (JSON.stringify(notificationStatus[data.account]) == JSON.stringify(data)) { + if ( + JSON.stringify(notificationStatus[data.account]) == JSON.stringify(data) + ) { return; } const playlist = playlists.find((pl) => pl.id == data.account); - if (!playlist) return; + if (!playlist) { + return; + } // Update notification status setNotificationStatus(prev => ({ @@ -82,7 +86,8 @@ export default function M3URefreshNotification() { } // Skip if already errored - if (notificationStatus[data.account]?.status === 'error') { + const currentStatus = notificationStatus[data.account]; + if (currentStatus && currentStatus.status === 'error') { return; } diff --git a/frontend/src/components/NotificationCenter.jsx b/frontend/src/components/NotificationCenter.jsx index b6bbdcfb..252e7da0 100644 --- a/frontend/src/components/NotificationCenter.jsx +++ b/frontend/src/components/NotificationCenter.jsx @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect, useState } from 'react'; +import React, { useEffect, useState, useCallback } from 'react'; import { useNavigate } from 'react-router-dom'; import { ActionIcon, @@ -20,19 +20,19 @@ import { useMantineTheme, } from '@mantine/core'; import { - AlertTriangle, - ArrowRight, Bell, Check, CheckCheck, Download, ExternalLink, + Info, + Settings, + AlertTriangle, + Megaphone, + X, Eye, EyeOff, - Info, - Megaphone, - Settings, - X, + ArrowRight, } from 'lucide-react'; import useNotificationsStore from '../store/notifications'; import { @@ -145,9 +145,7 @@ const NotificationItem = ({ notification, onDismiss, onAction, onClose }) => { color="gray" size="sm" onClick={handleDismiss} - pos='absolute' - top={8} - right={8} + style={{ position: 'absolute', top: 8, right: 8 }} > @@ -157,7 +155,7 @@ const NotificationItem = ({ notification, onDismiss, onAction, onClose }) => { {getNotificationIcon(notification.notification_type)} - + {notification.title} diff --git a/frontend/src/components/SeriesModal.jsx b/frontend/src/components/SeriesModal.jsx index 367e92a1..d22e6630 100644 --- a/frontend/src/components/SeriesModal.jsx +++ b/frontend/src/components/SeriesModal.jsx @@ -1,31 +1,31 @@ -import React, { useEffect, useState } from 'react'; +import React, { useState, useEffect } from 'react'; import { - ActionIcon, - Badge, Box, Button, - Divider, Flex, Group, Image, - Loader, - Modal, + Text, + Title, Select, + Badge, + Loader, Stack, + ActionIcon, + Modal, + Tabs, Table, + Divider, TableTbody, TableTd, TableTh, TableThead, TableTr, - Tabs, TabsList, TabsPanel, TabsTab, - Text, - Title, } from '@mantine/core'; -import { Copy, Play } from 'lucide-react'; +import { Play, Copy } from 'lucide-react'; import { copyToClipboard } from '../utils'; import useVODStore from '../store/useVODStore'; import useVideoStore from '../store/useVideoStore'; @@ -486,7 +486,7 @@ const SeriesModal = ({ series, opened, onClose }) => { size="xl" centered > - + {/* Backdrop image as background */} {displaySeries.backdrop_path && displaySeries.backdrop_path.length > 0 && ( @@ -495,42 +495,42 @@ const SeriesModal = ({ series, opened, onClose }) => { src={displaySeries.backdrop_path[0]} alt={`${displaySeries.name} backdrop`} fit="cover" - pos="absolute" - top={0} - left={0} - w={'100%'} - h={'100%'} - bdrs={8} style={{ + position: 'absolute', + top: 0, + left: 0, + width: '100%', + height: '100%', objectFit: 'cover', zIndex: 0, + borderRadius: 8, filter: 'blur(2px) brightness(0.5)', }} /> {/* Overlay for readability */} )} {/* Modal content above backdrop */} - + {loadingDetails && ( - + Loading series details and episodes... @@ -546,7 +546,9 @@ const SeriesModal = ({ series, opened, onClose }) => { Stream Selection - {loadingProviders && } + {loadingProviders && ( + + )} {providers.length === 0 && !loadingProviders && @@ -576,7 +578,7 @@ const SeriesModal = ({ series, opened, onClose }) => { value={selectedProvider?.id?.toString() || ''} onChange={(value) => onChangeSelectedProvider(value)} placeholder="Select stream..." - maw={350} + style={{ maxWidth: 350 }} disabled={loadingProviders} /> ) : null} @@ -608,11 +610,11 @@ const SeriesModal = ({ series, opened, onClose }) => { - Ep + Ep Title - Duration - Date - Action + Duration + Date + Action @@ -633,19 +635,19 @@ const SeriesModal = ({ series, opened, onClose }) => { {episode.name} {episode.genre && ( - + {episode.genre} )} - + {formatDuration(episode.duration_secs)} - + {getEpisodeAirdate(episode)} @@ -704,7 +706,7 @@ const SeriesModal = ({ series, opened, onClose }) => { ))} ) : ( - + No episodes found for this series. )} diff --git a/frontend/src/components/Sidebar.jsx b/frontend/src/components/Sidebar.jsx index 67f721cd..496a416c 100644 --- a/frontend/src/components/Sidebar.jsx +++ b/frontend/src/components/Sidebar.jsx @@ -66,7 +66,7 @@ const NavLink = ({ item, isActive, collapsed }) => { )} {!collapsed && item.badge && ( - + {item.badge} )} @@ -84,16 +84,17 @@ function NavGroup({ label, icon, paths, location, collapsed }) { .includes(location.pathname); return ( - - setOpen((o) => !o)} className={`navlink ${parentActive ? 'navlink-parent-active' : ''} ${open ? 'navlink-collapsed' : ''}`} + style={{ width: '100%' }} > {icon} {!collapsed && ( - + - + {open ? : } @@ -115,13 +116,13 @@ function NavGroup({ label, icon, paths, location, collapsed }) { {open && ( - + {paths.map((child) => { const active = location.pathname === child.path; return ( { @@ -259,15 +261,15 @@ const Sidebar = ({ collapsed, toggleDrawer, drawerWidth, miniDrawerWidth }) => { { { {/* Profile Section */} @@ -375,9 +377,7 @@ const Sidebar = ({ collapsed, toggleDrawer, drawerWidth, miniDrawerWidth }) => { {!collapsed && authUser && ( @@ -402,9 +402,7 @@ const Sidebar = ({ collapsed, toggleDrawer, drawerWidth, miniDrawerWidth }) => { {/* Version and Notification */} {!collapsed && ( v{appVersion?.version || '0.0.0'} @@ -415,9 +413,9 @@ const Sidebar = ({ collapsed, toggleDrawer, drawerWidth, miniDrawerWidth }) => { )} {collapsed && isAuthenticated && ( diff --git a/frontend/src/components/SystemEvents.jsx b/frontend/src/components/SystemEvents.jsx index df4bc087..1fcfd9db 100644 --- a/frontend/src/components/SystemEvents.jsx +++ b/frontend/src/components/SystemEvents.jsx @@ -171,17 +171,16 @@ const SystemEvents = () => { const [events, setEvents] = useState([]); const [totalEvents, setTotalEvents] = useState(0); const [isExpanded, setIsExpanded] = useState(false); + const { ref: cardRef, width: cardWidth } = useElementSize(); + const isNarrow = cardWidth < 650; const [isLoading, setIsLoading] = useState(false); - const [currentPage, setCurrentPage] = useState(1); const [eventsRefreshInterval, setEventsRefreshInterval] = useLocalStorage( 'events-refresh-interval', 0 ); const [eventsLimit, setEventsLimit] = useLocalStorage('events-limit', 100); - - const { ref: cardRef, width: cardWidth } = useElementSize(); - const isNarrow = cardWidth < 650; + const [currentPage, setCurrentPage] = useState(1); // Calculate offset based on current page and limit const offset = (currentPage - 1) * eventsLimit; @@ -225,13 +224,13 @@ const SystemEvents = () => { padding="sm" radius="md" withBorder - color="#fff" - w={'100%'} - maw={isExpanded ? '100%' : 800} - ml="auto" - mr="auto" style={{ + color: '#fff', backgroundColor: '#27272A', + width: '100%', + maxWidth: isExpanded ? '100%' : '800px', + marginLeft: 'auto', + marginRight: 'auto', transition: 'max-width 0.3s ease', }} > @@ -251,7 +250,7 @@ const SystemEvents = () => { min={10} max={1000} step={10} - w={130} + style={{ width: 130 }} />