Skip to content

Commit e2aad17

Browse files
committed
Allow store to create files and directories
1 parent 9c18acf commit e2aad17

9 files changed

Lines changed: 204 additions & 89 deletions

File tree

package-lock.json

Lines changed: 32 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@
1010
"preview": "vite preview"
1111
},
1212
"dependencies": {
13+
"@types/pako": "^2.0.1",
1314
"@types/uuid": "^9.0.4",
15+
"base64-js": "^1.5.1",
16+
"pako": "^2.1.0",
1417
"react": "^18.2.0",
1518
"react-dom": "^18.2.0",
1619
"sass": "^1.67.0",

src/App.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import "./App.css";
22
import Desktop from "./components/Desktop";
3-
import useConditionalContextMenu from "./hooks/useConditionalContextMenu";
43

54
function App() {
6-
useConditionalContextMenu();
75
return (
86
<div className="App">
97
<Desktop />

src/components/TopBar/SystemTray/PowerMenu/PowerMenu.scss

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
height: 20px;
1212
aspect-ratio: 1/1;
1313
width: auto;
14-
// path {
15-
// fill: white;
16-
// }
14+
path {
15+
fill: white;
16+
}
1717
}
1818
}

src/hooks/useCompression.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import pako from "pako";
2+
import base64js from "base64-js";
3+
4+
function useCompression() {
5+
function compress(data: string) {
6+
return base64js.fromByteArray(pako.deflate(data));
7+
}
8+
9+
function decompress(data: string) {
10+
return pako.inflate(base64js.toByteArray(data), { to: "string" });
11+
}
12+
13+
return { compress, decompress };
14+
}
15+
16+
export default useCompression;

src/hooks/useConditionalClick.ts

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import { useCallback, useEffect, useRef } from "react";
1+
import React, { useCallback, useEffect, useRef } from "react";
22

33
type EventHandlerMap =
44
| { type: "click" | "contextmenu"; handler: (e: MouseEvent) => void }
55
| { type: "keydown" | "keyup"; handler: (e: KeyboardEvent) => void };
66

7-
interface UseConditionalClickProps {
7+
interface UseConditionalClickProps<Element extends HTMLElement> {
88
/**
99
* Whether the `clickHandler` should be invoked on right click, left click,
1010
* or either of these.
@@ -21,34 +21,39 @@ interface UseConditionalClickProps {
2121
/**
2222
* The function to be invoked when a matching click is detected.
2323
*/
24-
clickHandler: () => void;
24+
clickHandler: (event: MouseEvent) => void;
2525

2626
/**
2727
* A reference to the element on which click events should be listened to.
2828
*/
29-
elementRef: React.RefObject<HTMLElement> | null;
29+
elementRef?: React.RefObject<Element> | null;
3030
}
3131

3232
/**
3333
* Allows either left click or right click to be handled only when the specified
3434
* modifier keys are also pressed.
3535
*/
36-
function useConditionalClick({
36+
function useConditionalClick<Element extends HTMLElement>({
3737
mouseButton,
3838
modifierKeys,
3939
clickHandler,
4040
elementRef,
41-
}: UseConditionalClickProps) {
41+
}: UseConditionalClickProps<Element>) {
4242
const keysDown = useRef(new Set<string>());
4343

44-
const onClick = useCallback(() => {
45-
if (modifierKeys) {
46-
for (const key of modifierKeys) {
47-
if (!keysDown.current.has(key)) return;
44+
const defaultRef = useRef<Element>(null);
45+
46+
const onClick = useCallback(
47+
(e: MouseEvent) => {
48+
if (modifierKeys) {
49+
for (const key of modifierKeys) {
50+
if (!keysDown.current.has(key)) return;
51+
}
4852
}
49-
}
50-
clickHandler();
51-
}, [clickHandler, modifierKeys]);
53+
clickHandler(e);
54+
},
55+
[clickHandler, modifierKeys]
56+
);
5257

5358
const onKeyDown = useCallback(
5459
(e: KeyboardEvent) => {
@@ -64,7 +69,7 @@ function useConditionalClick({
6469
}, []);
6570

6671
useEffect(() => {
67-
const ref = elementRef?.current;
72+
const ref = elementRef ? elementRef?.current : defaultRef?.current;
6873

6974
if (!ref) return;
7075

@@ -100,6 +105,10 @@ function useConditionalClick({
100105
});
101106
};
102107
}, [clickHandler, elementRef, mouseButton, onClick, onKeyDown, onKeyUp]);
108+
109+
return {
110+
ref: elementRef ?? defaultRef,
111+
};
103112
}
104113

105114
export default useConditionalClick;

src/hooks/useConditionalContextMenu.ts

Lines changed: 0 additions & 45 deletions
This file was deleted.

src/programs/FileBrowser/FileBrowser.tsx

Lines changed: 66 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
import React, { useEffect, useState } from "react";
22
import { ReactComponent as FolderIcon } from "../../assets/icons/folder-icon.svg";
33

4-
import { FSObject, isFSDirectory } from "../../stores/localFS";
4+
import useLocalFS, {
5+
FSDirectory,
6+
FSObject,
7+
isFSDirectory,
8+
} from "../../stores/localFS";
59
import useLocalFSWithHistory from "../../hooks/useLocalFSWithHistory";
610

711
import "./FileBrowser.scss";
812
import AppSideBar from "../../components/AppSideBar";
13+
import useCompression from "../../hooks/useCompression";
914
const defaultPath = "/home/user";
1015

1116
interface FileBrowserProps {
@@ -53,35 +58,74 @@ function TopBar({
5358
}
5459

5560
interface MainContentProps {
56-
dirContents: Record<string, FSObject>;
61+
currentDirectory: FSDirectory;
5762
openFSObject: (fsObject: FSObject) => void;
5863
}
5964

60-
function MainContent({ dirContents, openFSObject }: MainContentProps) {
65+
function MainContent({ currentDirectory, openFSObject }: MainContentProps) {
6166
const [selected, setSelected] = useState<string>("");
67+
const fs = useLocalFS();
68+
const { compress } = useCompression();
69+
70+
function handleRightClick(e: React.MouseEvent) {
71+
e.stopPropagation();
72+
e.preventDefault();
73+
//fs.createFile("test-create-file.txt", currentDirectory, compress("Hello world!"));
74+
}
75+
6276
return (
63-
<div className="file-browser__main-content">
64-
{Object.values<FSObject>(dirContents).map((fsObject) => (
65-
<div
66-
className={`file-browser__main-content__item ${
67-
fsObject.path === selected ? "active" : ""
68-
}`}
69-
onDoubleClick={() => openFSObject(fsObject)}
70-
onClick={() => setSelected(fsObject.path)}
71-
key={fsObject.path}
72-
>
73-
{isFSDirectory(fsObject) ? (
74-
<FolderIcon className="file-browser__main-content__item-icon" />
75-
) : null}
76-
<span className="file-browser__main-content__item-name">
77-
{fsObject.name}
78-
</span>
79-
</div>
77+
<div
78+
className="file-browser__main-content"
79+
onContextMenu={handleRightClick}
80+
>
81+
{Object.values<FSObject>(currentDirectory.contents).map((fsObject) => (
82+
<DirectoryOrFile
83+
fsObject={fsObject}
84+
openFSObject={openFSObject}
85+
selected={selected === fsObject.path}
86+
setSelected={setSelected}
87+
/>
8088
))}
8189
</div>
8290
);
8391
}
8492

93+
interface DirectoryOrFileProps {
94+
fsObject: FSObject;
95+
selected: boolean;
96+
openFSObject: (fsObject: FSObject) => void;
97+
setSelected: (path: string) => void;
98+
}
99+
100+
function DirectoryOrFile({
101+
fsObject,
102+
openFSObject,
103+
selected,
104+
setSelected,
105+
}: DirectoryOrFileProps) {
106+
function handleRightClick(event: React.MouseEvent) {
107+
event.stopPropagation();
108+
event.preventDefault();
109+
}
110+
111+
return (
112+
<div
113+
className={`file-browser__main-content__item ${selected ? "active" : ""}`}
114+
onDoubleClick={() => openFSObject(fsObject)}
115+
onClick={() => setSelected(fsObject.path)}
116+
key={fsObject.path}
117+
onContextMenu={handleRightClick}
118+
>
119+
{isFSDirectory(fsObject) ? (
120+
<FolderIcon className="file-browser__main-content__item-icon" />
121+
) : null}
122+
<span className="file-browser__main-content__item-name">
123+
{fsObject.name}
124+
</span>
125+
</div>
126+
);
127+
}
128+
85129
function FileBrowser({ path = defaultPath }: FileBrowserProps) {
86130
const fs = useLocalFSWithHistory(path);
87131

@@ -117,12 +161,12 @@ function FileBrowser({ path = defaultPath }: FileBrowserProps) {
117161
items={fs.favorites.map((fav) => ({
118162
title: fav.name,
119163
isActive: fav.path === fs.currentDirectory.path,
120-
onClick: () => fs.navToObject(fav),
164+
onClick: () => fs.navToPath(fav.path),
121165
}))}
122166
/>
123167

124168
<MainContent
125-
dirContents={fs.currentDirectory.contents}
169+
currentDirectory={fs.currentDirectory}
126170
openFSObject={fs.navToObject}
127171
/>
128172
<div className="file-browser__bottom-bar"></div>

0 commit comments

Comments
 (0)