mirror of
https://github.com/Dispatcharr/Dispatcharr.git
synced 2026-07-18 09:06:06 +00:00
Reverted styling/small syntax changes
This commit is contained in:
parent
8d7752c004
commit
a54bc2c513
7 changed files with 163 additions and 141 deletions
|
|
@ -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 */}
|
||||
<Flex justify="flex-end" p={3}>
|
||||
<Flex
|
||||
justify="flex-end"
|
||||
style={{
|
||||
padding: 3,
|
||||
}}
|
||||
>
|
||||
<CloseButton
|
||||
onClick={handleClose}
|
||||
onTouchEnd={handleClose}
|
||||
onMouseDown={(e) => 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 */}
|
||||
<Box
|
||||
pos="relative"
|
||||
style={{ position: 'relative' }}
|
||||
onMouseEnter={() => {
|
||||
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 && (
|
||||
<Box
|
||||
pos="absolute"
|
||||
top={0}
|
||||
left={0}
|
||||
right={0}
|
||||
p={'10px 10px 20px'}
|
||||
color={'white'}
|
||||
opacity={showOverlay ? 1 : 0}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
background: 'linear-gradient(rgba(0,0,0,0.8), transparent)',
|
||||
padding: '10px 10px 20px',
|
||||
color: 'white',
|
||||
pointerEvents: 'none', // Allow clicks to pass through to video controls
|
||||
transition: 'opacity 0.3s ease-in-out',
|
||||
opacity: showOverlay ? 1 : 0,
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
|
|
@ -724,7 +729,7 @@ export default function FloatingVideo() {
|
|||
{metadata.year && (
|
||||
<Text
|
||||
size="xs"
|
||||
c="dimmed"
|
||||
color="dimmed"
|
||||
style={{ textShadow: '1px 1px 2px rgba(0,0,0,0.8)' }}
|
||||
>
|
||||
{metadata.year}
|
||||
|
|
@ -736,14 +741,14 @@ export default function FloatingVideo() {
|
|||
{/* Loading overlay - only show when loading */}
|
||||
{isLoading && (
|
||||
<Box
|
||||
pos="absolute"
|
||||
top={0}
|
||||
left={0}
|
||||
w={'100%'}
|
||||
h={'100%'}
|
||||
display="flex"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.7)',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
|
|
@ -751,7 +756,7 @@ export default function FloatingVideo() {
|
|||
}}
|
||||
>
|
||||
<Loader color="cyan" size="md" />
|
||||
<Text c="white" size="sm" mt={10}>
|
||||
<Text color="white" size="sm" mt={10}>
|
||||
Loading {contentType === 'vod' ? 'video' : 'stream'}...
|
||||
</Text>
|
||||
</Box>
|
||||
|
|
@ -761,13 +766,13 @@ export default function FloatingVideo() {
|
|||
{/* Error message below video - doesn't block controls */}
|
||||
{!isLoading && loadError && (
|
||||
<Box
|
||||
p={10}
|
||||
style={{
|
||||
padding: '10px',
|
||||
backgroundColor: '#2d1b2e',
|
||||
borderTop: '1px solid #444',
|
||||
}}
|
||||
>
|
||||
<Text c="red" size="xs" ta="center">
|
||||
<Text color="red" size="xs" style={{ textAlign: 'center' }}>
|
||||
{loadError}
|
||||
</Text>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 }}
|
||||
>
|
||||
<X size={14} />
|
||||
</ActionIcon>
|
||||
|
|
@ -157,7 +155,7 @@ const NotificationItem = ({ notification, onDismiss, onAction, onClose }) => {
|
|||
<ThemeIcon color={typeColor} variant="light" size="md" radius="xl">
|
||||
{getNotificationIcon(notification.notification_type)}
|
||||
</ThemeIcon>
|
||||
<Box flex={1}>
|
||||
<Box style={{ flex: 1 }}>
|
||||
<Group gap="xs" mb={4}>
|
||||
<Text size="sm" fw={600} lineClamp={1}>
|
||||
{notification.title}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
>
|
||||
<Box pos="relative" mih={400}>
|
||||
<Box style={{ position: 'relative', minHeight: 400 }}>
|
||||
{/* 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 */}
|
||||
<Box
|
||||
pos="absolute"
|
||||
top={0}
|
||||
left={0}
|
||||
w={'100%'}
|
||||
h={'100%'}
|
||||
bdrs={8}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
background:
|
||||
'linear-gradient(180deg, rgba(24,24,27,0.85) 60%, rgba(24,24,27,1) 100%)',
|
||||
zIndex: 1,
|
||||
borderRadius: 8,
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Modal content above backdrop */}
|
||||
<Box pos="relative" style={{ zIndex: 2 }}>
|
||||
<Box style={{ position: 'relative', zIndex: 2 }}>
|
||||
<Stack spacing="md">
|
||||
{loadingDetails && (
|
||||
<Group spacing="xs" mb={8}>
|
||||
<Loader size="xs" />
|
||||
<Text size="xs" c="dimmed">
|
||||
<Text size="xs" color="dimmed">
|
||||
Loading series details and episodes...
|
||||
</Text>
|
||||
</Group>
|
||||
|
|
@ -546,7 +546,9 @@ const SeriesModal = ({ series, opened, onClose }) => {
|
|||
<Box mt="md">
|
||||
<Text size="sm" weight={500} mb={4}>
|
||||
Stream Selection
|
||||
{loadingProviders && <Loader size="xs" ml={8} />}
|
||||
{loadingProviders && (
|
||||
<Loader size="xs" style={{ marginLeft: 8 }} />
|
||||
)}
|
||||
</Text>
|
||||
{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 }) => {
|
|||
<Table striped highlightOnHover>
|
||||
<TableThead>
|
||||
<TableTr>
|
||||
<TableTh w={60}>Ep</TableTh>
|
||||
<TableTh style={{ width: '60px' }}>Ep</TableTh>
|
||||
<TableTh>Title</TableTh>
|
||||
<TableTh w={80}>Duration</TableTh>
|
||||
<TableTh w={60}>Date</TableTh>
|
||||
<TableTh w={80}>Action</TableTh>
|
||||
<TableTh style={{ width: '80px' }}>Duration</TableTh>
|
||||
<TableTh style={{ width: '60px' }}>Date</TableTh>
|
||||
<TableTh style={{ width: '80px' }}>Action</TableTh>
|
||||
</TableTr>
|
||||
</TableThead>
|
||||
<TableTbody>
|
||||
|
|
@ -633,19 +635,19 @@ const SeriesModal = ({ series, opened, onClose }) => {
|
|||
{episode.name}
|
||||
</Text>
|
||||
{episode.genre && (
|
||||
<Text size="xs" c="dimmed">
|
||||
<Text size="xs" color="dimmed">
|
||||
{episode.genre}
|
||||
</Text>
|
||||
)}
|
||||
</Stack>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Text size="xs" c="dimmed">
|
||||
<Text size="xs" color="dimmed">
|
||||
{formatDuration(episode.duration_secs)}
|
||||
</Text>
|
||||
</TableTd>
|
||||
<TableTd>
|
||||
<Text size="xs" c="dimmed">
|
||||
<Text size="xs" color="dimmed">
|
||||
{getEpisodeAirdate(episode)}
|
||||
</Text>
|
||||
</TableTd>
|
||||
|
|
@ -704,7 +706,7 @@ const SeriesModal = ({ series, opened, onClose }) => {
|
|||
))}
|
||||
</Tabs>
|
||||
) : (
|
||||
<Text c="dimmed" align="center" py="xl">
|
||||
<Text color="dimmed" align="center" py="xl">
|
||||
No episodes found for this series.
|
||||
</Text>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ const NavLink = ({ item, isActive, collapsed }) => {
|
|||
</Text>
|
||||
)}
|
||||
{!collapsed && item.badge && (
|
||||
<Text size="sm" c='#D4D4D8' style={{ whiteSpace: 'nowrap' }}>
|
||||
<Text size="sm" style={{ color: '#D4D4D8', whiteSpace: 'nowrap' }}>
|
||||
{item.badge}
|
||||
</Text>
|
||||
)}
|
||||
|
|
@ -84,16 +84,17 @@ function NavGroup({ label, icon, paths, location, collapsed }) {
|
|||
.includes(location.pathname);
|
||||
|
||||
return (
|
||||
<Box w='100%' pr={2}
|
||||
className={open ? 'navgroup-open' : ''}
|
||||
<Box
|
||||
style={{ width: '100%', paddingRight: 2 }}
|
||||
>
|
||||
<UnstyledButton w='100%'
|
||||
<UnstyledButton
|
||||
onClick={() => setOpen((o) => !o)}
|
||||
className={`navlink ${parentActive ? 'navlink-parent-active' : ''} ${open ? 'navlink-collapsed' : ''}`}
|
||||
style={{ width: '100%' }}
|
||||
>
|
||||
{icon}
|
||||
{!collapsed && (
|
||||
<Group justify="space-between" w='100%'>
|
||||
<Group justify="space-between" style={{ width: '100%' }}>
|
||||
<Text
|
||||
sx={{
|
||||
opacity: open ? 0 : 1,
|
||||
|
|
@ -107,7 +108,7 @@ function NavGroup({ label, icon, paths, location, collapsed }) {
|
|||
{label}
|
||||
</Text>
|
||||
|
||||
<Box alignItems="center" display='flex'>
|
||||
<Box alignItems="center" style={{ display: 'flex' }}>
|
||||
{open ? <ChevronDown size={16} /> : <ChevronRight size={16} />}
|
||||
</Box>
|
||||
</Group>
|
||||
|
|
@ -115,13 +116,13 @@ function NavGroup({ label, icon, paths, location, collapsed }) {
|
|||
</UnstyledButton>
|
||||
|
||||
{open && (
|
||||
<Box pt={10}>
|
||||
<Box style={{ paddingTop: 10 }}>
|
||||
<Stack gap="xs" pl={open ? 0 : 'lg'}>
|
||||
{paths.map((child) => {
|
||||
const active = location.pathname === child.path;
|
||||
return (
|
||||
<Box
|
||||
pl={collapsed ? 0 : 35}
|
||||
style={{ paddingLeft: collapsed ? 0 : 35 }}
|
||||
key={child.path}
|
||||
>
|
||||
<NavLink
|
||||
|
|
@ -247,11 +248,12 @@ const Sidebar = ({ collapsed, toggleDrawer, drawerWidth, miniDrawerWidth }) => {
|
|||
<AppShellNavbar
|
||||
width={{ base: collapsed ? miniDrawerWidth : drawerWidth }}
|
||||
p="xs"
|
||||
mih="100vh"
|
||||
display='flex'
|
||||
br='1px solid #2A2A2E'
|
||||
style={{
|
||||
backgroundColor: '#1A1A1E',
|
||||
// transition: 'width 0.3s ease',
|
||||
borderRight: '1px solid #2A2A2E',
|
||||
minHeight: '100vh',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
}}
|
||||
>
|
||||
|
|
@ -259,15 +261,15 @@ const Sidebar = ({ collapsed, toggleDrawer, drawerWidth, miniDrawerWidth }) => {
|
|||
<Group
|
||||
onClick={toggleDrawer}
|
||||
spacing="sm"
|
||||
display="flex"
|
||||
p={'16px 12px'}
|
||||
fz={18}
|
||||
fw={600}
|
||||
color="#FFFFFF"
|
||||
style={{
|
||||
cursor: 'pointer',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 12,
|
||||
padding: '16px 12px',
|
||||
fontSize: 18,
|
||||
fontWeight: 600,
|
||||
color: '#FFFFFF',
|
||||
justifyContent: collapsed ? 'center' : 'flex-start',
|
||||
whiteSpace: 'nowrap',
|
||||
}}
|
||||
|
|
@ -295,9 +297,9 @@ const Sidebar = ({ collapsed, toggleDrawer, drawerWidth, miniDrawerWidth }) => {
|
|||
<Stack
|
||||
gap="xs"
|
||||
mt="lg"
|
||||
flex={1}
|
||||
mih={0}
|
||||
style={{
|
||||
flex: 1,
|
||||
minHeight: 0,
|
||||
overflowY: 'auto',
|
||||
overflowX: 'hidden',
|
||||
}}
|
||||
|
|
@ -332,13 +334,13 @@ const Sidebar = ({ collapsed, toggleDrawer, drawerWidth, miniDrawerWidth }) => {
|
|||
|
||||
{/* Profile Section */}
|
||||
<Box
|
||||
mt='auto'
|
||||
p={16}
|
||||
display='flex'
|
||||
bt='1px solid #2A2A2E'
|
||||
style={{
|
||||
marginTop: 'auto',
|
||||
padding: '16px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 10,
|
||||
borderTop: '1px solid #2A2A2E',
|
||||
justifyContent: collapsed ? 'center' : 'flex-start',
|
||||
}}
|
||||
>
|
||||
|
|
@ -375,9 +377,7 @@ const Sidebar = ({ collapsed, toggleDrawer, drawerWidth, miniDrawerWidth }) => {
|
|||
|
||||
{!collapsed && authUser && (
|
||||
<Group
|
||||
gap="xs"
|
||||
w='100%'
|
||||
style={{ justifyContent: 'space-between' }}
|
||||
style={{ justifyContent: 'space-between', width: '100%' }}
|
||||
>
|
||||
<Group gap="xs">
|
||||
<Avatar src="" radius="xl" />
|
||||
|
|
@ -402,9 +402,7 @@ const Sidebar = ({ collapsed, toggleDrawer, drawerWidth, miniDrawerWidth }) => {
|
|||
{/* Version and Notification */}
|
||||
{!collapsed && (
|
||||
<Group
|
||||
gap="xs"
|
||||
p={'0 16px 16px'}
|
||||
style={{ justifyContent: 'space-between' }}
|
||||
style={{ padding: '0 16px 16px', justifyContent: 'space-between' }}
|
||||
>
|
||||
<Text size="xs" c="dimmed">
|
||||
v{appVersion?.version || '0.0.0'}
|
||||
|
|
@ -415,9 +413,9 @@ const Sidebar = ({ collapsed, toggleDrawer, drawerWidth, miniDrawerWidth }) => {
|
|||
)}
|
||||
{collapsed && isAuthenticated && (
|
||||
<Box
|
||||
p={'0 16px 16px'}
|
||||
display='flex'
|
||||
style={{
|
||||
padding: '0 16px 16px',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -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 }}
|
||||
/>
|
||||
<Select
|
||||
size="xs"
|
||||
|
|
@ -265,14 +264,14 @@ const SystemEvents = () => {
|
|||
{ value: '30', label: '30s' },
|
||||
{ value: '60', label: '1m' },
|
||||
]}
|
||||
w={120}
|
||||
style={{ width: 120 }}
|
||||
/>
|
||||
<Button
|
||||
size="xs"
|
||||
variant="subtle"
|
||||
onClick={fetchEvents}
|
||||
loading={isLoading}
|
||||
mt="auto"
|
||||
style={{ marginTop: 'auto' }}
|
||||
>
|
||||
Refresh
|
||||
</Button>
|
||||
|
|
@ -312,8 +311,8 @@ const SystemEvents = () => {
|
|||
<Stack
|
||||
gap="xs"
|
||||
mt="sm"
|
||||
mah="60vh"
|
||||
style={{
|
||||
maxHeight: '60vh',
|
||||
overflowY: 'auto',
|
||||
}}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,19 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Badge, Box, Button, Flex, Group, Image, Loader, Modal, Select, Stack, Text, Title, } from '@mantine/core';
|
||||
import { Copy, Play } from 'lucide-react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Flex,
|
||||
Group,
|
||||
Image,
|
||||
Text,
|
||||
Title,
|
||||
Select,
|
||||
Badge,
|
||||
Loader,
|
||||
Stack,
|
||||
Modal,
|
||||
} from '@mantine/core';
|
||||
import { Play, Copy } from 'lucide-react';
|
||||
import { copyToClipboard } from '../utils';
|
||||
import useVODStore from '../store/useVODStore';
|
||||
import useVideoStore from '../store/useVideoStore';
|
||||
|
|
@ -327,7 +340,7 @@ const VODModal = ({ vod, opened, onClose }) => {
|
|||
size="xl"
|
||||
centered
|
||||
>
|
||||
<Box pos="relative" mih={400}>
|
||||
<Box style={{ position: 'relative', minHeight: 400 }}>
|
||||
{/* Backdrop image as background */}
|
||||
{displayVOD.backdrop_path && displayVOD.backdrop_path.length > 0 && (
|
||||
<>
|
||||
|
|
@ -335,41 +348,41 @@ const VODModal = ({ vod, opened, onClose }) => {
|
|||
src={displayVOD.backdrop_path[0]}
|
||||
alt={`${displayVOD.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 */}
|
||||
<Box
|
||||
pos="absolute"
|
||||
top={0}
|
||||
left={0}
|
||||
w="100%"
|
||||
h="100%"
|
||||
bdrs={8}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
background:
|
||||
'linear-gradient(180deg, rgba(24,24,27,0.85) 60%, rgba(24,24,27,1) 100%)',
|
||||
zIndex: 1,
|
||||
borderRadius: 8,
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{/* Modal content above backdrop */}
|
||||
<Box pos="relative" style={{ zIndex: 2 }}>
|
||||
<Box style={{ position: 'relative', zIndex: 2 }}>
|
||||
<Stack spacing="md">
|
||||
{loadingDetails && (
|
||||
<Group spacing="xs" mb={8}>
|
||||
<Loader size="xs" />
|
||||
<Text size="xs" c="dimmed">
|
||||
<Text size="xs" color="dimmed">
|
||||
Loading additional details...
|
||||
</Text>
|
||||
</Group>
|
||||
|
|
@ -386,19 +399,19 @@ const VODModal = ({ vod, opened, onClose }) => {
|
|||
height={300}
|
||||
alt={displayVOD.name}
|
||||
fit="contain"
|
||||
bdrs={8}
|
||||
style={{ borderRadius: '8px' }}
|
||||
/>
|
||||
</Box>
|
||||
) : (
|
||||
<Box
|
||||
w={200}
|
||||
h={300}
|
||||
display="flex"
|
||||
bdrs={8}
|
||||
style={{
|
||||
width: 200,
|
||||
height: 300,
|
||||
backgroundColor: '#404040',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: '8px',
|
||||
flexShrink: 0,
|
||||
}}
|
||||
>
|
||||
|
|
@ -419,10 +432,12 @@ const VODModal = ({ vod, opened, onClose }) => {
|
|||
<Group spacing="md" align="flex-end" mt="md">
|
||||
{/* Provider Selection */}
|
||||
{providers.length > 0 && (
|
||||
<Box miw={200}>
|
||||
<Box style={{ minWidth: 200 }}>
|
||||
<Text size="sm" weight={500} mb={8}>
|
||||
Stream Selection
|
||||
{loadingProviders && <Loader size="xs" ml={8} />}
|
||||
{loadingProviders && (
|
||||
<Loader size="xs" style={{ marginLeft: 8 }} />
|
||||
)}
|
||||
</Text>
|
||||
{providers.length === 1 ? (
|
||||
<Group spacing="md">
|
||||
|
|
@ -439,7 +454,7 @@ const VODModal = ({ vod, opened, onClose }) => {
|
|||
value={selectedProvider?.id?.toString() || ''}
|
||||
onChange={(value) => onChangeSelectedProvider(value)}
|
||||
placeholder="Select stream..."
|
||||
miw={250}
|
||||
style={{ minWidth: 250 }}
|
||||
disabled={loadingProviders}
|
||||
/>
|
||||
)}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue