86 lines
2.2 KiB
TypeScript
86 lines
2.2 KiB
TypeScript
|
|
import React from 'react';
|
||
|
|
import type { MessageBlock } from '@/store/commStore';
|
||
|
|
|
||
|
|
interface FileBlockProps {
|
||
|
|
block: MessageBlock;
|
||
|
|
}
|
||
|
|
|
||
|
|
function formatFileSize(bytes: number | undefined): string {
|
||
|
|
if (typeof bytes !== 'number' || bytes <= 0) return '';
|
||
|
|
if (bytes < 1024) return `${bytes} B`;
|
||
|
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
||
|
|
if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
||
|
|
return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
|
||
|
|
}
|
||
|
|
|
||
|
|
const fileIcon = (
|
||
|
|
<svg
|
||
|
|
className="w-8 h-8 text-secondary-400"
|
||
|
|
fill="none"
|
||
|
|
viewBox="0 0 24 24"
|
||
|
|
stroke="currentColor"
|
||
|
|
aria-hidden="true"
|
||
|
|
>
|
||
|
|
<path
|
||
|
|
strokeLinecap="round"
|
||
|
|
strokeLinejoin="round"
|
||
|
|
strokeWidth={1.5}
|
||
|
|
d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z M14 2v6h6 M8 13h8 M8 17h5"
|
||
|
|
/>
|
||
|
|
</svg>
|
||
|
|
);
|
||
|
|
|
||
|
|
const downloadIcon = (
|
||
|
|
<svg
|
||
|
|
className="w-4 h-4"
|
||
|
|
fill="none"
|
||
|
|
viewBox="0 0 24 24"
|
||
|
|
stroke="currentColor"
|
||
|
|
aria-hidden="true"
|
||
|
|
>
|
||
|
|
<path
|
||
|
|
strokeLinecap="round"
|
||
|
|
strokeLinejoin="round"
|
||
|
|
strokeWidth={2}
|
||
|
|
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"
|
||
|
|
/>
|
||
|
|
</svg>
|
||
|
|
);
|
||
|
|
|
||
|
|
const FileBlock: React.FC<FileBlockProps> = ({ block }) => {
|
||
|
|
const { url, name, size } = block.block_data;
|
||
|
|
|
||
|
|
if (!url && !name) {
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
const fileName: string = name || 'Datei';
|
||
|
|
const fileSizeLabel = formatFileSize(size);
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="flex items-center gap-3 p-3 rounded-lg border border-secondary-200 bg-white shadow-sm">
|
||
|
|
<div className="flex-shrink-0">{fileIcon}</div>
|
||
|
|
<div className="flex-1 min-w-0">
|
||
|
|
<p className="text-sm font-medium text-secondary-700 truncate">{fileName}</p>
|
||
|
|
{fileSizeLabel && (
|
||
|
|
<p className="text-xs text-secondary-400">{fileSizeLabel}</p>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
{url && (
|
||
|
|
<a
|
||
|
|
href={url}
|
||
|
|
download={fileName}
|
||
|
|
target="_blank"
|
||
|
|
rel="noopener noreferrer"
|
||
|
|
className="flex-shrink-0 p-2 rounded-lg bg-primary-500 text-white hover:bg-primary-600 transition-colors"
|
||
|
|
aria-label={`Datei herunterladen: ${fileName}`}
|
||
|
|
>
|
||
|
|
{downloadIcon}
|
||
|
|
</a>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
};
|
||
|
|
|
||
|
|
export default FileBlock;
|