update
This commit is contained in:
@@ -43,31 +43,46 @@ function extractFileParams(messageParameters: Record<string, any>): FileParam[]
|
||||
return files;
|
||||
}
|
||||
|
||||
interface ImageLightboxProps {
|
||||
type OverlayMode = 'image' | 'pdf' | 'video';
|
||||
|
||||
interface ContentOverlayProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
previewUrl: string;
|
||||
mode: OverlayMode;
|
||||
contentUrl: string;
|
||||
downloadUrl: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
const ImageLightbox: React.FC<ImageLightboxProps> = ({ open, onClose, previewUrl, downloadUrl, name }) => (
|
||||
const ContentOverlay: React.FC<ContentOverlayProps> = ({ open, onClose, mode, contentUrl, downloadUrl, name }) => (
|
||||
<Dialog
|
||||
open={open}
|
||||
onClose={onClose}
|
||||
maxWidth="lg"
|
||||
fullWidth
|
||||
slotProps={{ paper: { sx: { bgcolor: 'black', m: 1 } } }}
|
||||
slotProps={{ paper: { sx: { bgcolor: mode === 'image' ? 'black' : 'background.paper', 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">
|
||||
{mode === 'image' && (
|
||||
<Box
|
||||
component="img"
|
||||
src={contentUrl}
|
||||
alt={name}
|
||||
sx={{ maxWidth: '100%', maxHeight: '85vh', display: 'block', objectFit: 'contain' }}
|
||||
/>
|
||||
)}
|
||||
{mode === 'pdf' && (
|
||||
<Box component="iframe" src={contentUrl} sx={{ width: '100%', height: '80vh', border: 'none', display: 'block' }} title={name} />
|
||||
)}
|
||||
{mode === 'video' && (
|
||||
<Box
|
||||
component="video"
|
||||
controls
|
||||
src={contentUrl}
|
||||
sx={{ maxWidth: '100%', maxHeight: '85vh', display: 'block' }}
|
||||
/>
|
||||
)}
|
||||
<Tooltip title="Schlie\u00DFen">
|
||||
<IconButton
|
||||
onClick={onClose}
|
||||
size="small"
|
||||
@@ -76,7 +91,6 @@ const ImageLightbox: React.FC<ImageLightboxProps> = ({ open, onClose, previewUrl
|
||||
<CloseIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
{/* Download button */}
|
||||
<Tooltip title="Herunterladen">
|
||||
<IconButton
|
||||
component="a"
|
||||
@@ -90,7 +104,6 @@ const ImageLightbox: React.FC<ImageLightboxProps> = ({ open, onClose, previewUrl
|
||||
<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 }}
|
||||
@@ -103,17 +116,27 @@ const ImageLightbox: React.FC<ImageLightboxProps> = ({ open, onClose, previewUrl
|
||||
);
|
||||
|
||||
const FileMessageContent: React.FC<FileMessageContentProps> = ({ messageParameters, isOwnMessage }) => {
|
||||
const [lightboxFile, setLightboxFile] = useState<FileParam | null>(null);
|
||||
const [overlayFile, setOverlayFile] = useState<{ file: FileParam; mode: OverlayMode } | null>(null);
|
||||
const files = extractFileParams(messageParameters);
|
||||
if (files.length === 0) return null;
|
||||
|
||||
const getOverlayMode = (file: FileParam): OverlayMode | null => {
|
||||
const mime = file.mimetype ?? '';
|
||||
if (mime.startsWith('image/') && file.previewAvailable === 'yes') return 'image';
|
||||
if (mime === 'application/pdf') return 'pdf';
|
||||
if (mime.startsWith('video/')) return 'video';
|
||||
return null;
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{files.map((file, idx) => {
|
||||
const downloadUrl = `/api/nextcloud/talk/files/${file.id}/download${file.path ? `?path=${encodeURIComponent(file.path)}` : ''}`;
|
||||
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 mime = file.mimetype ?? '';
|
||||
const isImage = mime.startsWith('image/') && file.previewAvailable === 'yes';
|
||||
const isAudio = mime.startsWith('audio/');
|
||||
const overlayMode = getOverlayMode(file);
|
||||
|
||||
if (isImage) {
|
||||
return (
|
||||
@@ -122,7 +145,7 @@ const FileMessageContent: React.FC<FileMessageContentProps> = ({ messageParamete
|
||||
component="img"
|
||||
src={thumbUrl}
|
||||
alt={file.name}
|
||||
onClick={() => setLightboxFile(file)}
|
||||
onClick={() => setOverlayFile({ file, mode: 'image' })}
|
||||
sx={{
|
||||
maxWidth: '100%',
|
||||
maxHeight: 200,
|
||||
@@ -154,9 +177,32 @@ const FileMessageContent: React.FC<FileMessageContentProps> = ({ messageParamete
|
||||
);
|
||||
}
|
||||
|
||||
if (isAudio) {
|
||||
return (
|
||||
<Box key={idx} sx={{ mt: 0.5 }}>
|
||||
<Box
|
||||
component="audio"
|
||||
controls
|
||||
src={downloadUrl}
|
||||
sx={{ width: '100%', display: 'block' }}
|
||||
/>
|
||||
<Typography variant="caption" sx={{ opacity: 0.7, fontSize: '0.7rem', display: 'block', mt: 0.25 }} noWrap>
|
||||
{file.name}
|
||||
</Typography>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Box
|
||||
key={idx}
|
||||
onClick={() => {
|
||||
if (overlayMode) {
|
||||
setOverlayFile({ file, mode: overlayMode });
|
||||
} else {
|
||||
window.open(downloadUrl, '_blank', 'noopener,noreferrer');
|
||||
}
|
||||
}}
|
||||
sx={{
|
||||
mt: 0.5,
|
||||
display: 'flex',
|
||||
@@ -164,9 +210,15 @@ const FileMessageContent: React.FC<FileMessageContentProps> = ({ messageParamete
|
||||
gap: 1,
|
||||
p: 0.75,
|
||||
borderRadius: 1,
|
||||
cursor: 'pointer',
|
||||
bgcolor: isOwnMessage
|
||||
? 'rgba(255,255,255,0.15)'
|
||||
: (theme) => theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.05)' : 'rgba(0,0,0,0.05)',
|
||||
: (theme: any) => theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.05)' : 'rgba(0,0,0,0.05)',
|
||||
'&:hover': {
|
||||
bgcolor: isOwnMessage
|
||||
? 'rgba(255,255,255,0.25)'
|
||||
: (theme: any) => theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.1)' : 'rgba(0,0,0,0.1)',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<InsertDriveFileIcon fontSize="small" sx={{ opacity: 0.8, flexShrink: 0 }} />
|
||||
@@ -188,6 +240,7 @@ const FileMessageContent: React.FC<FileMessageContentProps> = ({ messageParamete
|
||||
download={file.name}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
sx={{ flexShrink: 0, color: 'inherit' }}
|
||||
>
|
||||
<DownloadIcon fontSize="small" />
|
||||
@@ -197,13 +250,18 @@ const FileMessageContent: React.FC<FileMessageContentProps> = ({ messageParamete
|
||||
);
|
||||
})}
|
||||
|
||||
{lightboxFile && (
|
||||
<ImageLightbox
|
||||
{overlayFile && (
|
||||
<ContentOverlay
|
||||
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}
|
||||
onClose={() => setOverlayFile(null)}
|
||||
mode={overlayFile.mode}
|
||||
contentUrl={
|
||||
overlayFile.mode === 'image'
|
||||
? `/api/nextcloud/talk/files/${overlayFile.file.id}/preview?w=1200&h=1200`
|
||||
: `/api/nextcloud/talk/files/${overlayFile.file.id}/download${overlayFile.file.path ? `?path=${encodeURIComponent(overlayFile.file.path)}` : ''}`
|
||||
}
|
||||
downloadUrl={`/api/nextcloud/talk/files/${overlayFile.file.id}/download${overlayFile.file.path ? `?path=${encodeURIComponent(overlayFile.file.path)}` : ''}`}
|
||||
name={overlayFile.file.name}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user