update
This commit is contained in:
@@ -1,10 +1,13 @@
|
|||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
import Box from '@mui/material/Box';
|
import Box from '@mui/material/Box';
|
||||||
import Typography from '@mui/material/Typography';
|
import Typography from '@mui/material/Typography';
|
||||||
import IconButton from '@mui/material/IconButton';
|
import IconButton from '@mui/material/IconButton';
|
||||||
import Tooltip from '@mui/material/Tooltip';
|
import Tooltip from '@mui/material/Tooltip';
|
||||||
|
import Dialog from '@mui/material/Dialog';
|
||||||
|
import DialogContent from '@mui/material/DialogContent';
|
||||||
import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile';
|
import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile';
|
||||||
import DownloadIcon from '@mui/icons-material/Download';
|
import DownloadIcon from '@mui/icons-material/Download';
|
||||||
|
import CloseIcon from '@mui/icons-material/Close';
|
||||||
|
|
||||||
interface FileParam {
|
interface FileParam {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -40,7 +43,67 @@ function extractFileParams(messageParameters: Record<string, any>): FileParam[]
|
|||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ImageLightboxProps {
|
||||||
|
open: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
previewUrl: string;
|
||||||
|
downloadUrl: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ImageLightbox: React.FC<ImageLightboxProps> = ({ open, onClose, previewUrl, downloadUrl, name }) => (
|
||||||
|
<Dialog
|
||||||
|
open={open}
|
||||||
|
onClose={onClose}
|
||||||
|
maxWidth="lg"
|
||||||
|
fullWidth
|
||||||
|
slotProps={{ paper: { sx: { bgcolor: 'black', m: 1 } } }}
|
||||||
|
>
|
||||||
|
<DialogContent sx={{ p: 0, position: 'relative', display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: 200 }}>
|
||||||
|
<Box
|
||||||
|
component="img"
|
||||||
|
src={previewUrl}
|
||||||
|
alt={name}
|
||||||
|
sx={{ maxWidth: '100%', maxHeight: '85vh', display: 'block', objectFit: 'contain' }}
|
||||||
|
/>
|
||||||
|
{/* Close button */}
|
||||||
|
<Tooltip title="Schließen">
|
||||||
|
<IconButton
|
||||||
|
onClick={onClose}
|
||||||
|
size="small"
|
||||||
|
sx={{ position: 'absolute', top: 8, right: 8, bgcolor: 'rgba(0,0,0,0.5)', color: 'white', '&:hover': { bgcolor: 'rgba(0,0,0,0.75)' } }}
|
||||||
|
>
|
||||||
|
<CloseIcon fontSize="small" />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
{/* Download button */}
|
||||||
|
<Tooltip title="Herunterladen">
|
||||||
|
<IconButton
|
||||||
|
component="a"
|
||||||
|
href={downloadUrl}
|
||||||
|
download={name}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
size="small"
|
||||||
|
sx={{ position: 'absolute', top: 8, right: 44, bgcolor: 'rgba(0,0,0,0.5)', color: 'white', '&:hover': { bgcolor: 'rgba(0,0,0,0.75)' } }}
|
||||||
|
>
|
||||||
|
<DownloadIcon fontSize="small" />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
{/* Filename */}
|
||||||
|
<Typography
|
||||||
|
variant="caption"
|
||||||
|
sx={{ position: 'absolute', bottom: 8, left: 0, right: 0, textAlign: 'center', color: 'rgba(255,255,255,0.7)', px: 2 }}
|
||||||
|
noWrap
|
||||||
|
>
|
||||||
|
{name}
|
||||||
|
</Typography>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
|
||||||
const FileMessageContent: React.FC<FileMessageContentProps> = ({ messageParameters, isOwnMessage }) => {
|
const FileMessageContent: React.FC<FileMessageContentProps> = ({ messageParameters, isOwnMessage }) => {
|
||||||
|
const [lightboxFile, setLightboxFile] = useState<FileParam | null>(null);
|
||||||
const files = extractFileParams(messageParameters);
|
const files = extractFileParams(messageParameters);
|
||||||
if (files.length === 0) return null;
|
if (files.length === 0) return null;
|
||||||
|
|
||||||
@@ -48,30 +111,45 @@ const FileMessageContent: React.FC<FileMessageContentProps> = ({ messageParamete
|
|||||||
<>
|
<>
|
||||||
{files.map((file, idx) => {
|
{files.map((file, idx) => {
|
||||||
const downloadUrl = `/api/nextcloud/talk/files/${file.id}/download${file.path ? `?path=${encodeURIComponent(file.path)}` : ''}`;
|
const downloadUrl = `/api/nextcloud/talk/files/${file.id}/download${file.path ? `?path=${encodeURIComponent(file.path)}` : ''}`;
|
||||||
const previewUrl = `/api/nextcloud/talk/files/${file.id}/preview?w=400&h=400`;
|
const thumbUrl = `/api/nextcloud/talk/files/${file.id}/preview?w=400&h=400`;
|
||||||
|
const fullUrl = `/api/nextcloud/talk/files/${file.id}/preview?w=1200&h=1200`;
|
||||||
const isImage = file.mimetype?.startsWith('image/') && file.previewAvailable === 'yes';
|
const isImage = file.mimetype?.startsWith('image/') && file.previewAvailable === 'yes';
|
||||||
|
|
||||||
if (isImage) {
|
if (isImage) {
|
||||||
return (
|
return (
|
||||||
<Box key={idx} sx={{ mt: 0.5 }}>
|
<Box key={idx} sx={{ mt: 0.5 }}>
|
||||||
<a href={downloadUrl} target="_blank" rel="noopener noreferrer" download={file.name}>
|
|
||||||
<Box
|
<Box
|
||||||
component="img"
|
component="img"
|
||||||
src={previewUrl}
|
src={thumbUrl}
|
||||||
alt={file.name}
|
alt={file.name}
|
||||||
|
onClick={() => setLightboxFile(file)}
|
||||||
sx={{
|
sx={{
|
||||||
maxWidth: '100%',
|
maxWidth: '100%',
|
||||||
maxHeight: 200,
|
maxHeight: 200,
|
||||||
borderRadius: 1,
|
borderRadius: 1,
|
||||||
display: 'block',
|
display: 'block',
|
||||||
cursor: 'pointer',
|
cursor: 'zoom-in',
|
||||||
'&:hover': { opacity: 0.9 },
|
'&:hover': { opacity: 0.9 },
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</a>
|
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mt: 0.25 }}>
|
||||||
<Typography variant="caption" sx={{ opacity: 0.7, fontSize: '0.7rem' }}>
|
<Typography variant="caption" sx={{ opacity: 0.7, fontSize: '0.7rem' }} noWrap>
|
||||||
{file.name}
|
{file.name}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
<Tooltip title="Herunterladen">
|
||||||
|
<IconButton
|
||||||
|
size="small"
|
||||||
|
component="a"
|
||||||
|
href={downloadUrl}
|
||||||
|
download={file.name}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
sx={{ color: 'inherit', p: 0.25, flexShrink: 0 }}
|
||||||
|
>
|
||||||
|
<DownloadIcon sx={{ fontSize: '0.9rem' }} />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -93,12 +171,7 @@ const FileMessageContent: React.FC<FileMessageContentProps> = ({ messageParamete
|
|||||||
>
|
>
|
||||||
<InsertDriveFileIcon fontSize="small" sx={{ opacity: 0.8, flexShrink: 0 }} />
|
<InsertDriveFileIcon fontSize="small" sx={{ opacity: 0.8, flexShrink: 0 }} />
|
||||||
<Box sx={{ flex: 1, minWidth: 0 }}>
|
<Box sx={{ flex: 1, minWidth: 0 }}>
|
||||||
<Typography
|
<Typography variant="body2" noWrap title={file.name} sx={{ fontWeight: 500, lineHeight: 1.2 }}>
|
||||||
variant="body2"
|
|
||||||
noWrap
|
|
||||||
title={file.name}
|
|
||||||
sx={{ fontWeight: 500, lineHeight: 1.2 }}
|
|
||||||
>
|
|
||||||
{file.name}
|
{file.name}
|
||||||
</Typography>
|
</Typography>
|
||||||
{file.size && (
|
{file.size && (
|
||||||
@@ -123,6 +196,16 @@ const FileMessageContent: React.FC<FileMessageContentProps> = ({ messageParamete
|
|||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
||||||
|
{lightboxFile && (
|
||||||
|
<ImageLightbox
|
||||||
|
open
|
||||||
|
onClose={() => setLightboxFile(null)}
|
||||||
|
previewUrl={`/api/nextcloud/talk/files/${lightboxFile.id}/preview?w=1200&h=1200`}
|
||||||
|
downloadUrl={`/api/nextcloud/talk/files/${lightboxFile.id}/download${lightboxFile.path ? `?path=${encodeURIComponent(lightboxFile.path)}` : ''}`}
|
||||||
|
name={lightboxFile.name}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user