Implemented desktop folder

This commit is contained in:
Prozilla 2023-12-11 23:05:26 +01:00
parent a307eda1d1
commit cc796ea8bb
No known key found for this signature in database
GPG key ID: 5858DFE71CAF31EE
10 changed files with 216 additions and 117 deletions

View file

@ -0,0 +1,72 @@
import { VirtualFile } from "../../../features/virtual-drive/virtualFile.js";
import { VirtualFolder } from "../../../features/virtual-drive/virtualFolder.js";
import { FilePreview } from "./FilePreview.jsx";
import { FolderPreview } from "./FolderPreview.jsx";
import styles from "./DirectoryList.module.css";
/**
* @callback fileEvent
* @param {object} event
* @param {VirtualFile} file
*/
/**
* @callback folderEvent
* @param {object} event
* @param {VirtualFolder} folder
*/
/**
* @param {object} props
* @param {VirtualFolder} props.directory
* @param {boolean} props.showHidden
* @param {string} props.folderClassname
* @param {string} props.fileClassname
* @param {fileEvent} props.onContextMenuFile
* @param {folderEvent} props.onContextMenuFolder
* @param {fileEvent} props.onClickFile
* @param {folderEvent} props.onClickFolder
*/
export function DirectoryList({ directory, showHidden = false, folderClassname, fileClassname,
onContextMenuFile, onContextMenuFolder, onClickFile, onClickFolder }) {
if (!directory)
return null;
// const folders = directory.getSubFolders(showHidden);
// const files = directory.getFiles(showHidden);
return <>
{directory?.getSubFolders(showHidden)?.map((folder) =>
<button
key={folder.id}
tabIndex={0}
className={`${styles["Folder-button"]} ${folderClassname}`}
onContextMenu={(event) => {
onContextMenuFolder(event, folder);
}}
onClick={(event) => {
onClickFolder(event, folder);
}}
>
<FolderPreview folder={folder}/>
<p>{folder.name}</p>
</button>
)}
{directory?.getFiles(showHidden)?.map((file) =>
<button
key={file.id}
tabIndex={0}
className={`${styles["File-button"]} ${fileClassname}`}
onContextMenu={(event) => {
onContextMenuFile(event, file);
}}
onClick={(event) => {
onClickFile(event, file);
}}
>
<FilePreview file={file}/>
<p>{file.id}</p>
</button>
)}
</>;
}

View file

@ -0,0 +1,43 @@
.File-button, .Folder-button {
display: flex;
gap: 0.5rem;
flex-direction: column;
align-items: center;
justify-content: center;
width: calc(var(--scale) * 7.5);
height: calc(var(--scale) * 7.5);
padding: 0.5rem;
background: none;
border: none;
border-radius: 0.5rem;
outline: none;
cursor: pointer;
transition: background-color 100ms ease-in-out;
}
.File-button:hover, .Folder-button:hover,
.File-button:focus-visible, .Folder-button:focus-visible {
background-color: hsla(var(--background-color-a-hsl), 35%);
}
.File-button svg, .Folder-button > div {
width: 50%;
height: auto;
aspect-ratio: 1;
}
.Folder-button > div > svg {
width: 100%;
height: 100%;
aspect-ratio: 1;
}
.File-button p, .Folder-button p {
max-width: 100%;
margin: 0;
word-wrap: break-word;
}
.Folder-button > div {
position: relative;
}

View file

@ -11,8 +11,7 @@ import { QuickAccessButton } from "./QuickAccessButton.jsx";
import { useDialogBox } from "../../../hooks/modals/dialogBox.js"; import { useDialogBox } from "../../../hooks/modals/dialogBox.js";
import Vector2 from "../../../features/math/vector2.js"; import Vector2 from "../../../features/math/vector2.js";
import { DIALOG_CONTENT_TYPES } from "../../../constants/modals.js"; import { DIALOG_CONTENT_TYPES } from "../../../constants/modals.js";
import { FilePreview } from "./FilePreview.jsx"; import { DirectoryList } from "./DirectoryList.jsx";
import { FolderPreview } from "./FolderPreview.jsx";
export function FileExplorer({ startPath, app }) { export function FileExplorer({ startPath, app }) {
const virtualRoot = useVirtualRoot(); const virtualRoot = useVirtualRoot();
@ -135,33 +134,19 @@ export function FileExplorer({ startPath, app }) {
<QuickAccessButton name={"Images"} onClick={() => { changeDirectory("~/Images"); }} icon={faImage}/> <QuickAccessButton name={"Images"} onClick={() => { changeDirectory("~/Images"); }} icon={faImage}/>
</div> </div>
<div id="main" className={styles.Main}> <div id="main" className={styles.Main}>
{currentDirectory?.getSubFolders(showHidden)?.map((folder, index) => <DirectoryList
<button key={index} tabIndex={0} className={styles["Folder-button"]} directory={currentDirectory}
onContextMenu={(event) => { showHidden={showHidden}
onContextMenuFolder(event, { name: folder.name }); onClickFile={(event, file) => {
}} event.preventDefault();
onClick={() => { windowsManager.openFile(file);
changeDirectory(folder.linkedPath ?? folder.name); }}
}} onClickFolder={(event, folder) => {
> changeDirectory(folder.linkedPath ?? folder.name);
<FolderPreview folder={folder}/> }}
<p>{folder.name}</p> onContextMenuFile={onContextMenuFile}
</button> onContextMenuFolder={onContextMenuFolder}
)} />
{currentDirectory?.getFiles(showHidden)?.map((file, index) =>
<button key={index} tabIndex={0} className={styles["File-button"]}
onContextMenu={(event) => {
onContextMenuFile(event, { file });
}}
onClick={(event) => {
event.preventDefault();
windowsManager.openFile(file);
}}
>
<FilePreview file={file}/>
<p>{file.id}</p>
</button>
)}
</div> </div>
</div> </div>
</div> </div>

View file

@ -120,88 +120,3 @@
padding: 0.5rem; padding: 0.5rem;
overflow: auto; overflow: auto;
} }
.File-button, .Folder-button {
display: flex;
gap: 0.5rem;
flex-direction: column;
align-items: center;
justify-content: center;
width: calc(var(--scale) * 7.5);
height: calc(var(--scale) * 7.5);
padding: 0.5rem;
background: none;
border: none;
border-radius: 0.5rem;
outline: none;
cursor: pointer;
transition: background-color 100ms ease-in-out;
}
.File-button:hover, .Folder-button:hover,
.File-button:focus-visible, .Folder-button:focus-visible {
background-color: hsla(var(--background-color-a-hsl), 35%);
}
.File-button-preview {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
overflow: hidden;
}
.File-button-preview > * {
width: 100%;
height: 100%;
object-fit: contain;
}
.File-button-preview > img {
height: auto;
max-height: 100%;
border-radius: 0.5rem;
}
.File-button svg, .Folder-button > div {
width: 50%;
height: auto;
aspect-ratio: 1;
}
.Folder-button > div > svg {
width: 100%;
height: 100%;
aspect-ratio: 1;
}
.File-button p, .Folder-button p {
max-width: 100%;
margin: 0;
word-wrap: break-word;
}
.Folder-button > div {
position: relative;
}
.Folder-link-icon {
position: absolute;
display: flex;
justify-content: flex-end;
align-items: flex-end;
top: 0;
left: 0;
width: 92.5%;
height: 87.5%;
}
.Folder-link-icon svg {
width: 55%;
height: auto;
aspect-ratio: 1;
}
.Folder-link-icon svg * {
fill: var(--background-color-b);
}

View file

@ -1,6 +1,6 @@
import { faFile, faFileInvoice, faFileLines } from "@fortawesome/free-solid-svg-icons"; import { faFile, faFileInvoice, faFileLines } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import styles from "./FileExplorer.module.css"; import styles from "./FilePreview.module.css";
import { VirtualFile } from "../../../features/virtual-drive/virtualFile.js"; import { VirtualFile } from "../../../features/virtual-drive/virtualFile.js";
/** /**

View file

@ -0,0 +1,19 @@
.File-button-preview {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
overflow: hidden;
}
.File-button-preview > * {
width: 100%;
height: 100%;
object-fit: contain;
}
.File-button-preview > img {
height: auto;
max-height: 100%;
border-radius: 0.5rem;
}

View file

@ -1,6 +1,6 @@
import { faFolder, faLink } from "@fortawesome/free-solid-svg-icons"; import { faFolder, faLink } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import styles from "./FileExplorer.module.css"; import styles from "./FolderPreview.module.css";
import { VirtualFolder } from "../../../features/virtual-drive/virtualFolder.js"; import { VirtualFolder } from "../../../features/virtual-drive/virtualFolder.js";
/** /**

View file

@ -0,0 +1,20 @@
.Folder-link-icon {
position: absolute;
display: flex;
justify-content: flex-end;
align-items: flex-end;
top: 0;
left: 0;
width: 92.5%;
height: 87.5%;
}
.Folder-link-icon svg {
width: 55%;
height: auto;
aspect-ratio: 1;
}
.Folder-link-icon svg * {
fill: var(--background-color-b);
}

View file

@ -9,12 +9,15 @@ import { useWindowsManager } from "../../hooks/windows/windowsManagerContext.js"
import { useContextMenu } from "../../hooks/modals/contextMenu.js"; import { useContextMenu } from "../../hooks/modals/contextMenu.js";
import { FALLBACK_WALLPAPER } from "../../constants/desktop.js"; import { FALLBACK_WALLPAPER } from "../../constants/desktop.js";
import { reloadViewport } from "../../features/utils/browser.js"; import { reloadViewport } from "../../features/utils/browser.js";
import { useVirtualRoot } from "../../hooks/virtual-drive/virtualRootContext.js";
import { DirectoryList } from "../applications/file-explorer/DirectoryList.jsx";
export const Desktop = memo(() => { export const Desktop = memo(() => {
const settingsManager = useSettingsManager(); const settingsManager = useSettingsManager();
const [wallpaper, setWallpaper] = useState(null); const [wallpaper, setWallpaper] = useState(null);
const [modalsManager, modals] = useModals(); const [modalsManager, modals] = useModals();
const windowsManager = useWindowsManager(); const windowsManager = useWindowsManager();
const virtualRoot = useVirtualRoot();
const { onContextMenu } = useContextMenu({ const { onContextMenu } = useContextMenu({
modalsManager, modalsManager,
options: { options: {
@ -31,6 +34,8 @@ export const Desktop = memo(() => {
})(); })();
}, [settingsManager]); }, [settingsManager]);
const directory = virtualRoot.navigate("~/Desktop");
const onError = () => { const onError = () => {
const settings = settingsManager.get(SettingsManager.VIRTUAL_PATHS.desktop); const settings = settingsManager.get(SettingsManager.VIRTUAL_PATHS.desktop);
settings.set("wallpaper", FALLBACK_WALLPAPER); settings.set("wallpaper", FALLBACK_WALLPAPER);
@ -41,11 +46,25 @@ export const Desktop = memo(() => {
className={styles.Container} className={styles.Container}
onContextMenu={onContextMenu} onContextMenu={onContextMenu}
> >
<ModalsView modalsManager={modalsManager} modals={modals}/>
<div className={styles.Content}>
<DirectoryList
directory={directory}
fileClassname={styles["Item"]}
folderClassname={styles["Item"]}
onClickFile={(event, file) => {
event.preventDefault();
windowsManager.openFile(file);
}}
onClickFolder={(event, { linkedPath, path }) => {
windowsManager.open("file-explorer", { startPath: linkedPath ?? path });
}}
/>
</div>
{wallpaper {wallpaper
? <img src={wallpaper} className={styles.Wallpaper} alt="Desktop wallpaper" onError={onError}/> ? <img src={wallpaper} className={styles.Wallpaper} alt="Desktop wallpaper" onError={onError}/>
: null : null
} }
<ModalsView modalsManager={modalsManager} modals={modals}/>
</div> </div>
</>); </>);
}); });

View file

@ -16,3 +16,29 @@
object-fit: cover; object-fit: cover;
pointer-events: none; pointer-events: none;
} }
.Content {
--scale: 1rem;
position: absolute;
display: flex;
flex-direction: column;
flex-wrap: wrap;
align-content: flex-start;
justify-content: flex-start;
top: 0;
left: 0;
width: 100%;
height: 100%;
padding: 0.5rem;
z-index: 1;
}
.Item {
padding: 0.25rem;
text-shadow: 0.1rem 0.1rem 0.2rem hsla(var(--background-color-a-hsl), 50%);
}
.Item > svg, .Item > div > svg {
filter: drop-shadow(0.1rem 0.1rem 0.2rem hsla(var(--background-color-a-hsl), 50%));
}