This commit is contained in:
nikec 2023-12-02 00:19:46 +01:00
parent 98ff6a7986
commit 71180cbac4
3 changed files with 137 additions and 2 deletions

View file

@ -0,0 +1,130 @@
import { X } from '@phosphor-icons/react';
import { Grid, useGrid } from '@virtual-grid/react';
import { memo, useEffect, useRef, useState } from 'react';
import { byteSize, ExplorerItem, getExplorerItemData, getItemFilePath } from '@sd/client';
import { Button, ProgressBar } from '@sd/ui';
import { useExplorerContext } from '../Context';
import { FileThumb } from '../FilePath/Thumb';
type Item = { item: ExplorerItem; size: number; progress: number };
export const CopyProgress = () => {
const explorer = useExplorerContext();
const [[items], setItems] = useState<[Map<number, Item>]>([new Map()]);
const scrollRef = useRef<HTMLDivElement>(null);
const grid = useGrid({ scrollRef, count: items.size, size: { height: 80 } });
useEffect(() => {
if (items.size !== 0 || !explorer.items || explorer.items.length === 0) return;
setItems([
new Map(
explorer.items.slice(0, 10).map((item, i) => {
const filePath = getItemFilePath(item);
const size = filePath?.size_in_bytes_bytes;
return [
i,
{
item,
size: size
? Number(byteSize(size).original)
: Math.floor(Math.random() * 1000000),
progress: 0
}
];
})
)
]);
}, [explorer.items, items.size]);
useEffect(() => {
const interval = setInterval(() => {
let finished = 0;
let change = false;
const updated = [...items].map(([i, item]) => {
let progress = item.progress;
if (progress === item.size) {
finished++;
return [i, item] as const;
}
if (Math.random() < 0.5) {
let difference = item.size - item.progress;
if (item.progress <= item.size / 2) difference = difference / 2;
progress += Math.floor(Math.random() * difference) + 1;
change = true;
}
if (progress === item.size) finished++;
return [i, { ...item, progress }] as const;
});
if (finished === items.size) clearInterval(interval);
if (change) setItems([new Map(updated)]);
}, 750);
return () => clearInterval(interval);
}, [items]);
return (
<div className="fixed bottom-12 right-4 z-50 w-96 overflow-hidden rounded-md border border-app-line bg-app/95 backdrop-blur">
<div className="flex items-center justify-between rounded-b-md border-b border-app-line/50 bg-app-darkBox px-3 py-2 shadow-md">
<h2 className="text-sm font-medium">Copying</h2>
<Button size="icon" onClick={() => setItems([new Map()])}>
<X />
</Button>
</div>
<div ref={scrollRef} className="h-full max-h-96 overflow-auto">
<Grid grid={grid}>
{(index) => {
const item = items.get(index);
if (!item) return null;
return (
<div key={index} className="flex h-full w-full items-center px-4">
<Thumb item={item.item} />
<div className="flex w-full flex-col overflow-hidden">
<span className="max-w-[90%] truncate text-sm font-medium">
{getExplorerItemData(item.item).fullName}
</span>
<span className="mb-1.5 text-xs text-ink-dull">
{`${byteSize(item.progress)}`} / {`${byteSize(item.size)}`}
{item.progress === 0
? ' - Waiting'
: item.progress < item.size
? ' - Copying'
: ' - Done'}
</span>
<ProgressBar
pending={item.progress === 0}
value={item.progress}
total={item.size}
/>
</div>
</div>
);
}}
</Grid>
</div>
</div>
);
};
const Thumb = memo(({ item }: { item: ExplorerItem }) => {
return (
<FileThumb
data={item}
className="mr-4"
frame
blackBars
frameClassName="!border"
size={40}
/>
);
});

View file

@ -17,6 +17,8 @@ import { ExplorerPath, PATH_BAR_HEIGHT } from './View/ExplorerPath';
import 'react-slidedown/lib/slidedown.css';
import { CopyProgress } from './CopyProgress';
interface Props {
emptyNotice?: ExplorerViewProps['emptyNotice'];
contextMenu?: () => ReactNode;
@ -102,8 +104,11 @@ export default function Explorer(props: PropsWithChildren<Props>) {
</div>
</div>
</ExplorerContextMenu>
{showPathBar && <ExplorerPath />}
<CopyProgress />
{explorerStore.showInspector && (
<Inspector
className="no-scrollbar absolute right-1.5 top-0 pb-3 pl-3 pr-1.5"

View file

@ -25,7 +25,7 @@ export const ProgressBar = memo((props: ProgressBarProps) => {
if (props.pending) {
return (
<div className="indeterminate-progress-bar h-1 bg-app-button">
<div className="indeterminate-progress-bar h-1 w-[95%] bg-app-button">
<div className="indeterminate-progress-bar__progress bg-accent"></div>
</div>
);
@ -33,7 +33,7 @@ export const ProgressBar = memo((props: ProgressBarProps) => {
return (
<ProgressPrimitive.Root
value={percentage}
className={clsx('h-1 w-[94%] overflow-hidden rounded-full bg-app-button')}
className={clsx('h-1 w-[95%] overflow-hidden rounded-full bg-app-button')}
>
<ProgressPrimitive.Indicator
style={{ width: `${percentage}%` }}