Updated file explorer + added file importing

This commit is contained in:
Prozilla 2024-05-23 23:12:51 +02:00
parent e74765e2c8
commit 35c06deb3c
No known key found for this signature in database
GPG key ID: 5858DFE71CAF31EE
7 changed files with 106 additions and 17 deletions

View file

@ -55,7 +55,7 @@ export default tseslint.config(
"comma-spacing": "off",
"@typescript-eslint/comma-spacing": "warn",
"@typescript-eslint/no-unused-vars": [
"error",
"warn",
{
"argsIgnorePattern": "^_"
}

View file

@ -26,6 +26,9 @@ import { WindowProps } from "../../windows/WindowView";
import { VirtualFolder } from "../../../features/virtual-drive/folder/virtualFolder";
import { VirtualFile } from "../../../features/virtual-drive/file/virtualFile";
import { VirtualFolderLink } from "../../../features/virtual-drive/folder/virtualFolderLink";
import ImportButton from "./ImportButton";
import { useAlert } from "../../../hooks/modals/alert";
import { VirtualRoot } from "../../../features/virtual-drive/root/virtualRoot";
interface FileExplorerProps extends WindowProps {
startPath?: string;
@ -44,6 +47,7 @@ export function FileExplorer({ startPath, selectorMode, Footer, onSelectionChang
const windowsManager = useWindowsManager();
const [showHidden] = useState(true);
const { history, stateIndex, pushState, undo, redo, undoAvailable, redoAvailable } = useHistory<string>(currentDirectory.path);
const { alert } = useAlert();
const { openWindowedModal } = useWindowedModal();
const { onContextMenu: onContextMenuFile } = useContextMenu({ Actions: (props) =>
@ -119,6 +123,24 @@ export function FileExplorer({ startPath, selectorMode, Footer, onSelectionChang
}
}, [history, stateIndex, virtualRoot]);
useEffect(() => {
const onError = (error: { message: string }) => {
alert({
title: error.message,
text: "You have exceeded the virtual drive capacity. Files and folders will not be saved until more storage is freed.",
iconUrl: AppsManager.getAppIconUrl(APPS.FILE_EXPLORER),
size: new Vector2(300, 200),
single: true,
});
};
virtualRoot.on(VirtualRoot.EVENT_NAMES.ERROR, onError);
return () => {
virtualRoot.off(VirtualRoot.EVENT_NAMES.ERROR, onError);
};
}, []);
const onPathChange = (event: Event) => {
setPath((event.target as HTMLInputElement).value);
};
@ -188,16 +210,16 @@ export function FileExplorer({ startPath, selectorMode, Footer, onSelectionChang
tabIndex={0}
className={styles["Icon-button"]}
onClick={() => {
openWindowedModal({
title: "Error",
iconUrl: AppsManager.getAppIconUrl(APPS.FILE_EXPLORER),
size: new Vector2(300, 150),
Modal: (props) =>
<DialogBox {...props}>
<p>This folder is protected.</p>
<button data-type={DIALOG_CONTENT_TYPES.CloseButton}>Ok</button>
</DialogBox>
});
// openWindowedModal({
// title: "Error",
// iconUrl: AppsManager.getAppIconUrl(APPS.FILE_EXPLORER),
// size: new Vector2(300, 150),
// Modal: (props) =>
// <DialogBox {...props}>
// <p>This folder is protected.</p>
// <button data-type={DIALOG_CONTENT_TYPES.CloseButton}>Ok</button>
// </DialogBox>
// });
// if (currentDirectory.canBeEdited) {
// onNew(event);
@ -219,6 +241,7 @@ export function FileExplorer({ startPath, selectorMode, Footer, onSelectionChang
onKeyDown={onKeyDown as unknown as KeyboardEventHandler}
placeholder="Enter a path..."
/>
<ImportButton directory={currentDirectory}/>
<button title="Search" tabIndex={0} className={styles["Icon-button"]}>
<FontAwesomeIcon icon={faSearch}/>
</button>

View file

@ -0,0 +1,42 @@
import { FormEventHandler, ReactElement } from "react";
import styles from "./FileExplorer.module.css";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faDownload } from "@fortawesome/free-solid-svg-icons";
import { VirtualFile } from "../../../features/virtual-drive/file/virtualFile";
import { VirtualFolder } from "../../../features/virtual-drive/folder";
interface ImportButtonProps {
directory: VirtualFolder;
}
export default function ImportButton({ directory }: ImportButtonProps): ReactElement {
const onChange = (event: InputEvent) => {
const files = (event.target as HTMLInputElement).files;
Array.from(files).forEach((file: File) => {
const { name, extension } = VirtualFile.convertId(file.name);
const reader = new FileReader();
reader.onload = (event: Event) => {
const { result } = event.target as FileReader;
// Create a file with the same name and extension, with a base64 string as a source
directory.createFile(name, extension, (virtualFile) => {
virtualFile.setSource(result as string);
});
};
reader.readAsDataURL(file);
});
};
return <label title="Import" tabIndex={0} className={styles["Icon-button"]}>
<input
type="file"
id="import"
multiple
style={{ display: "none" }}
onChange={onChange as unknown as FormEventHandler}
/>
<FontAwesomeIcon icon={faDownload}/>
</label>;
}

View file

@ -7,8 +7,10 @@
}
.File-button, .Folder-button {
--gap: 0.25rem;
display: flex;
gap: 0.25rem;
gap: var(--gap);
flex-direction: column;
align-items: center;
justify-content: center;
@ -41,9 +43,16 @@
word-wrap: break-word;
}
.File-icon, .Folder-icon {
max-height: calc(100% - 1rem - var(--gap));
border-radius: inherit;
}
.File-icon div, .Folder-icon div {
width: 100%;
height: 100%;
border-radius: inherit;
overflow: hidden;
}
.File-icon svg, .Folder-icon svg {

View file

@ -1,7 +1,4 @@
.Image-preview {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
overflow: hidden;
pointer-events: none;
@ -16,5 +13,7 @@
.Image-preview > img {
height: auto;
max-height: 100%;
border-radius: 0.5rem;
width: auto;
max-width: 100%;
border-radius: inherit;
}

View file

@ -5,6 +5,12 @@ export class StorageManager {
if (key == null || value == null)
return;
const exceededMaxStorage = this.getByteSize(value) > this.MAX_BYTES;
if (exceededMaxStorage) {
throw new Error("Failed to store value: storage capacity exceeded.");
}
localStorage.setItem(key, value);
}

View file

@ -18,6 +18,10 @@ export class VirtualRoot extends VirtualFolder {
initiated: boolean = false;
loadedDefaultData: boolean = false;
static EVENT_NAMES = {
ERROR: "error"
};
constructor() {
super("root");
this.root = this;
@ -141,7 +145,13 @@ export class VirtualRoot extends VirtualFolder {
if (data == null)
return;
StorageManager.store("data", data);
try {
StorageManager.store("data", data);
} catch (error) {
this.emit(VirtualRoot.EVENT_NAMES.ERROR, {
message: "Failed to save data"
});
}
}
/**