Calude güncellemesi FileManager optimizasyon
This commit is contained in:
parent
a01ce1533a
commit
b9550acda2
3 changed files with 681 additions and 761 deletions
|
|
@ -25,6 +25,8 @@ export interface FileManagerClipboard {
|
||||||
operation: 'copy' | 'cut'
|
operation: 'copy' | 'cut'
|
||||||
items: FileItem[]
|
items: FileItem[]
|
||||||
sourceFolder?: string
|
sourceFolder?: string
|
||||||
|
/** Tenant the items were copied/cut from. Paste is rejected across tenants. */
|
||||||
|
sourceTenantId?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FileManagerState {
|
export interface FileManagerState {
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,4 +1,12 @@
|
||||||
import { forwardRef, useState, useEffect, type ChangeEvent, type MouseEvent } from 'react'
|
import {
|
||||||
|
forwardRef,
|
||||||
|
memo,
|
||||||
|
useState,
|
||||||
|
useEffect,
|
||||||
|
type ChangeEvent,
|
||||||
|
type MouseEvent,
|
||||||
|
type ReactNode,
|
||||||
|
} from 'react'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import {
|
import {
|
||||||
FaFolder,
|
FaFolder,
|
||||||
|
|
@ -120,6 +128,28 @@ const getFileTypeLabel = (item: FileItemType, translate: (key: string) => string
|
||||||
return extension?.toUpperCase() || translate('::FileManager.File')
|
return extension?.toUpperCase() || translate('::FileManager.File')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Defined at module level: nesting it inside FileItem would remount the <img>
|
||||||
|
// (and restart the download) on every parent render.
|
||||||
|
const ImagePreview = ({ src, alt, fallback }: { src: string; alt: string; fallback: ReactNode }) => {
|
||||||
|
const [imageError, setImageError] = useState(false)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="w-full h-full bg-gray-100 dark:bg-gray-700 rounded flex items-center justify-center overflow-hidden">
|
||||||
|
{!imageError ? (
|
||||||
|
<img
|
||||||
|
src={src}
|
||||||
|
alt={alt}
|
||||||
|
loading="lazy"
|
||||||
|
className="max-w-full max-h-full object-cover"
|
||||||
|
onError={() => setImageError(true)}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div className="flex items-center justify-center w-full h-full">{fallback}</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const FileItem = forwardRef<HTMLDivElement, FileItemProps>((props, ref) => {
|
const FileItem = forwardRef<HTMLDivElement, FileItemProps>((props, ref) => {
|
||||||
const {
|
const {
|
||||||
item,
|
item,
|
||||||
|
|
@ -332,28 +362,6 @@ const FileItem = forwardRef<HTMLDivElement, FileItemProps>((props, ref) => {
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
// Resim preview komponenti
|
|
||||||
const ImagePreview = ({ src, alt }: { src: string; alt: string }) => {
|
|
||||||
const [imageError, setImageError] = useState(false)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="w-full h-full bg-gray-100 dark:bg-gray-700 rounded flex items-center justify-center overflow-hidden">
|
|
||||||
{!imageError ? (
|
|
||||||
<img
|
|
||||||
src={src}
|
|
||||||
alt={alt}
|
|
||||||
className="max-w-full max-h-full object-cover"
|
|
||||||
onError={() => setImageError(true)}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<div className="flex items-center justify-center w-full h-full">
|
|
||||||
{getFileIcon(item, false)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (viewMode === 'list') {
|
if (viewMode === 'list') {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -389,7 +397,11 @@ const FileItem = forwardRef<HTMLDivElement, FileItemProps>((props, ref) => {
|
||||||
{/* File Icon or Preview */}
|
{/* File Icon or Preview */}
|
||||||
<div className="w-8 h-8">
|
<div className="w-8 h-8">
|
||||||
{item.type === 'file' && item.mimeType?.startsWith('image/') ? (
|
{item.type === 'file' && item.mimeType?.startsWith('image/') ? (
|
||||||
<ImagePreview src={FILE_URL(item.path, item.tenantId)} alt={item.name} />
|
<ImagePreview
|
||||||
|
src={FILE_URL(item.path, item.tenantId)}
|
||||||
|
alt={item.name}
|
||||||
|
fallback={getFileIcon(item, false)}
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="w-full h-full flex items-center justify-center">
|
<div className="w-full h-full flex items-center justify-center">
|
||||||
{getFileIcon(item, false)}
|
{getFileIcon(item, false)}
|
||||||
|
|
@ -484,7 +496,11 @@ const FileItem = forwardRef<HTMLDivElement, FileItemProps>((props, ref) => {
|
||||||
<div className="flex justify-center mb-3">
|
<div className="flex justify-center mb-3">
|
||||||
{item.type === 'file' && item.mimeType?.startsWith('image/') ? (
|
{item.type === 'file' && item.mimeType?.startsWith('image/') ? (
|
||||||
<div className="w-16 h-16">
|
<div className="w-16 h-16">
|
||||||
<ImagePreview src={FILE_URL(item.path, item.tenantId)} alt={item.name} />
|
<ImagePreview
|
||||||
|
src={FILE_URL(item.path, item.tenantId)}
|
||||||
|
alt={item.name}
|
||||||
|
fallback={getFileIcon(item, false)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex justify-center">{getFileIcon(item, true)}</div>
|
<div className="flex justify-center">{getFileIcon(item, true)}</div>
|
||||||
|
|
@ -535,4 +551,4 @@ const FileItem = forwardRef<HTMLDivElement, FileItemProps>((props, ref) => {
|
||||||
|
|
||||||
FileItem.displayName = 'FileItem'
|
FileItem.displayName = 'FileItem'
|
||||||
|
|
||||||
export default FileItem
|
export default memo(FileItem)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue