mirror of
https://github.com/DrizzleTime/Foxel.git
synced 2026-09-08 17:16:50 +08:00
refactor: Remove unused props from GridView component and clean up related code
This commit is contained in:
@@ -121,8 +121,6 @@ const FileExplorerPage = memo(function FileExplorerPage() {
|
|||||||
onSelectRange={handleSelectRange}
|
onSelectRange={handleSelectRange}
|
||||||
onOpen={handleOpenEntry}
|
onOpen={handleOpenEntry}
|
||||||
onContextMenu={openContextMenu}
|
onContextMenu={openContextMenu}
|
||||||
onCreateDir={() => setCreatingDir(true)}
|
|
||||||
onGoUp={goUp}
|
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<FileListView
|
<FileListView
|
||||||
|
|||||||
@@ -7,20 +7,14 @@ import { EmptyState } from './EmptyState';
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
entries: VfsEntry[];
|
entries: VfsEntry[];
|
||||||
thumbs: Record<string,string>;
|
thumbs: Record<string, string>;
|
||||||
// ...existing code...
|
|
||||||
// selected was single entry before; now use selectedEntries for multi-select
|
|
||||||
selectedEntries: string[];
|
selectedEntries: string[];
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
path: string;
|
path: string;
|
||||||
// onSelect: clicked entry, additive indicates Ctrl/Cmd click to toggle
|
|
||||||
onSelect: (e: VfsEntry, additive?: boolean) => void;
|
onSelect: (e: VfsEntry, additive?: boolean) => void;
|
||||||
// onSelectRange: called when marquee/selecting multiple by box
|
|
||||||
onSelectRange: (names: string[]) => void;
|
onSelectRange: (names: string[]) => void;
|
||||||
onOpen: (e: VfsEntry) => void;
|
onOpen: (e: VfsEntry) => void;
|
||||||
onContextMenu: (e: React.MouseEvent, entry: VfsEntry) => void;
|
onContextMenu: (e: React.MouseEvent, entry: VfsEntry) => void;
|
||||||
onCreateDir: () => void;
|
|
||||||
onGoUp: () => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const formatSize = (size: number) => {
|
const formatSize = (size: number) => {
|
||||||
@@ -30,14 +24,12 @@ const formatSize = (size: number) => {
|
|||||||
return (size / 1024 / 1024 / 1024).toFixed(1) + ' GB';
|
return (size / 1024 / 1024 / 1024).toFixed(1) + ' GB';
|
||||||
};
|
};
|
||||||
|
|
||||||
export const GridView: React.FC<Props> = ({ entries, thumbs, selectedEntries, loading, path, onSelect, onSelectRange, onOpen, onContextMenu, onCreateDir, onGoUp }) => {
|
export const GridView: React.FC<Props> = ({ entries, thumbs, selectedEntries, loading, path, onSelect, onSelectRange, onOpen, onContextMenu }) => {
|
||||||
const { token } = theme.useToken();
|
const { token } = theme.useToken();
|
||||||
|
|
||||||
// refs for marquee selection
|
|
||||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||||
const itemRefs = useRef<Record<string, HTMLDivElement | null>>({});
|
const itemRefs = useRef<Record<string, HTMLDivElement | null>>({});
|
||||||
const startRef = useRef<{x:number,y:number} | null>(null);
|
const startRef = useRef<{ x: number, y: number } | null>(null);
|
||||||
const [rect, setRect] = useState<{left:number,top:number,width:number,height:number} | null>(null);
|
const [rect, setRect] = useState<{ left: number, top: number, width: number, height: number } | null>(null);
|
||||||
const [selecting, setSelecting] = useState(false);
|
const [selecting, setSelecting] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -52,12 +44,11 @@ export const GridView: React.FC<Props> = ({ entries, thumbs, selectedEntries, lo
|
|||||||
const height = Math.abs(cy - s.y);
|
const height = Math.abs(cy - s.y);
|
||||||
setRect({ left, top, width, height });
|
setRect({ left, top, width, height });
|
||||||
};
|
};
|
||||||
const onUp = () => { // 不需要 MouseEvent 参数,避免未使用警告
|
const onUp = () => {
|
||||||
if (!startRef.current) return;
|
if (!startRef.current) return;
|
||||||
setSelecting(false);
|
setSelecting(false);
|
||||||
const r = rect;
|
const r = rect;
|
||||||
if (r) {
|
if (r) {
|
||||||
// compute intersecting items
|
|
||||||
const container = containerRef.current;
|
const container = containerRef.current;
|
||||||
if (container) {
|
if (container) {
|
||||||
const sel: string[] = [];
|
const sel: string[] = [];
|
||||||
@@ -89,17 +80,14 @@ export const GridView: React.FC<Props> = ({ entries, thumbs, selectedEntries, lo
|
|||||||
}, [selecting, rect, entries, onSelectRange]);
|
}, [selecting, rect, entries, onSelectRange]);
|
||||||
|
|
||||||
const handleMouseDown = (e: React.MouseEvent) => {
|
const handleMouseDown = (e: React.MouseEvent) => {
|
||||||
// only left button and not on an item actionable element
|
|
||||||
if (e.button !== 0) return;
|
if (e.button !== 0) return;
|
||||||
// start marquee if click on empty space inside container
|
|
||||||
const target = e.target as HTMLElement;
|
const target = e.target as HTMLElement;
|
||||||
if (target.closest('.fx-grid-item')) {
|
if (target.closest('.fx-grid-item')) {
|
||||||
return; // clicks on item handled separately
|
return;
|
||||||
}
|
}
|
||||||
startRef.current = { x: e.clientX, y: e.clientY };
|
startRef.current = { x: e.clientX, y: e.clientY };
|
||||||
setSelecting(true);
|
setSelecting(true);
|
||||||
setRect({ left: e.clientX, top: e.clientY, width: 0, height: 0 });
|
setRect({ left: e.clientX, top: e.clientY, width: 0, height: 0 });
|
||||||
// prevent text selection
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -108,29 +96,28 @@ export const GridView: React.FC<Props> = ({ entries, thumbs, selectedEntries, lo
|
|||||||
{entries.map(ent => {
|
{entries.map(ent => {
|
||||||
const isImg = thumbs[ent.name];
|
const isImg = thumbs[ent.name];
|
||||||
const ext = ent.name.split('.').pop()?.toLowerCase();
|
const ext = ent.name.split('.').pop()?.toLowerCase();
|
||||||
const isPictureType = ['png','jpg','jpeg','gif','webp','svg'].includes(ext || '');
|
const isPictureType = ['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg'].includes(ext || '');
|
||||||
const isSelected = selectedEntries.includes(ent.name);
|
const isSelected = selectedEntries.includes(ent.name);
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={ent.name}
|
key={ent.name}
|
||||||
ref={(el) => { itemRefs.current[ent.name] = el; }} // 确保函数不返回值,匹配 Ref 类型
|
ref={(el) => { itemRefs.current[ent.name] = el; }}
|
||||||
className={['fx-grid-item', isSelected ? 'selected' : '', ent.is_dir? 'dir':'file'].join(' ')}
|
className={['fx-grid-item', isSelected ? 'selected' : '', ent.is_dir ? 'dir' : 'file'].join(' ')}
|
||||||
onClick={(ev) => {
|
onClick={(ev) => {
|
||||||
// click selection: support ctrl/cmd to toggle
|
|
||||||
const additive = ev.ctrlKey || ev.metaKey;
|
const additive = ev.ctrlKey || ev.metaKey;
|
||||||
onSelect(ent, additive);
|
onSelect(ent, additive);
|
||||||
}}
|
}}
|
||||||
onDoubleClick={() => onOpen(ent)}
|
onDoubleClick={() => onOpen(ent)}
|
||||||
onContextMenu={(e)=> onContextMenu(e, ent)}
|
onContextMenu={(e) => onContextMenu(e, ent)}
|
||||||
style={{ userSelect:'none' }}
|
style={{ userSelect: 'none' }}
|
||||||
>
|
>
|
||||||
<div className="thumb" style={{ background: ent.is_dir ? 'linear-gradient(#fafafa,#f2f2f2)' : '#fff' }}>
|
<div className="thumb" style={{ background: ent.is_dir ? 'linear-gradient(#fafafa,#f2f2f2)' : '#fff' }}>
|
||||||
{ent.is_dir && <FolderFilled style={{ fontSize:32, color: token.colorPrimary }} />}
|
{ent.is_dir && <FolderFilled style={{ fontSize: 32, color: token.colorPrimary }} />}
|
||||||
{!ent.is_dir && (isImg ? <img src={isImg} alt={ent.name} style={{ maxWidth:'100%', maxHeight:'100%'}} /> : isPictureType ? <PictureOutlined style={{ fontSize:32, color:'#8c8c8c' }} /> : getFileIcon(ent.name,32))}
|
{!ent.is_dir && (isImg ? <img src={isImg} alt={ent.name} style={{ maxWidth: '100%', maxHeight: '100%' }} /> : isPictureType ? <PictureOutlined style={{ fontSize: 32, color: '#8c8c8c' }} /> : getFileIcon(ent.name, 32))}
|
||||||
{ent.type === 'mount' && <span className="badge">M</span>}
|
{ent.type === 'mount' && <span className="badge">M</span>}
|
||||||
</div>
|
</div>
|
||||||
<Tooltip title={ent.name}><div className="name ellipsis" style={{ userSelect:'none' }}>{ent.name}</div></Tooltip>
|
<Tooltip title={ent.name}><div className="name ellipsis" style={{ userSelect: 'none' }}>{ent.name}</div></Tooltip>
|
||||||
<div className="meta ellipsis" style={{ fontSize:11, color: token.colorTextSecondary, userSelect:'none' }}>{ent.is_dir ? '目录' : formatSize(ent.size)}</div>
|
<div className="meta ellipsis" style={{ fontSize: 11, color: token.colorTextSecondary, userSelect: 'none' }}>{ent.is_dir ? '目录' : formatSize(ent.size)}</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
@@ -148,8 +135,8 @@ export const GridView: React.FC<Props> = ({ entries, thumbs, selectedEntries, lo
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{loading && <div style={{ width:'100%', textAlign:'center', padding:40 }}><Spin /></div>}
|
{loading && <div style={{ width: '100%', textAlign: 'center', padding: 40 }}><Spin /></div>}
|
||||||
{!loading && entries.length === 0 && <EmptyState isRoot={path==='/' } onCreateDir={onCreateDir} onGoUp={onGoUp} />}
|
{!loading && entries.length === 0 && <EmptyState isRoot={path === '/'} />}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user