diff --git a/package-lock.json b/package-lock.json
index 11c12ba..0813e75 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -22,6 +22,7 @@
"react-draggable": "^4.4.5",
"react-scripts": "5.0.1",
"react-svg": "^16.1.18",
+ "react-tabs": "^6.0.2",
"web-vitals": "^2.1.4"
},
"devDependencies": {
@@ -14960,6 +14961,26 @@
"react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0"
}
},
+ "node_modules/react-tabs": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/react-tabs/-/react-tabs-6.0.2.tgz",
+ "integrity": "sha512-aQXTKolnM28k3KguGDBSAbJvcowOQr23A+CUJdzJtOSDOtTwzEaJA+1U4KwhNL9+Obe+jFS7geuvA7ICQPXOnQ==",
+ "dependencies": {
+ "clsx": "^2.0.0",
+ "prop-types": "^15.5.0"
+ },
+ "peerDependencies": {
+ "react": "^18.0.0"
+ }
+ },
+ "node_modules/react-tabs/node_modules/clsx": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz",
+ "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/read-cache": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
diff --git a/package.json b/package.json
index 0cb9d9a..e0433b6 100644
--- a/package.json
+++ b/package.json
@@ -20,6 +20,7 @@
"react-draggable": "^4.4.5",
"react-scripts": "5.0.1",
"react-svg": "^16.1.18",
+ "react-tabs": "^6.0.2",
"web-vitals": "^2.1.4"
},
"scripts": {
diff --git a/src/App.jsx b/src/App.jsx
index b704074..7a5cb83 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -4,7 +4,7 @@ import { WindowsManagerProvider } from "./hooks/windows/WindowsManagerContext.js
import { WindowsView } from "./components/windows/WindowsView.jsx";
import { VirtualRootProvider } from "./hooks/virtual-drive/VirtualRootContext.js";
import { Desktop } from "./components/desktop/Desktop.jsx";
-import { SettingsProvider } from "./hooks/settings/SettingsContext.js";
+import { SettingsManagerProvider } from "./hooks/settings/SettingsContext.js";
import { ModalsView } from "./components/modals/ModalsView.jsx";
import { useEffect } from "react";
@@ -24,14 +24,14 @@ function App() {
return (
-
+
-
+
);
diff --git a/src/components/applications/settings/AboutSettings.jsx b/src/components/applications/settings/AboutSettings.jsx
new file mode 100644
index 0000000..ece35ff
--- /dev/null
+++ b/src/components/applications/settings/AboutSettings.jsx
@@ -0,0 +1,42 @@
+import { Button } from "../../utils/Button.jsx";
+import styles from "./Settings.module.css";
+import utilStyles from "../../../styles/utils.module.css";
+import Vector2 from "../../../features/math/vector2.js";
+import { useWindowsManager } from "../../../hooks/windows/WindowsManagerContext.js";
+import { useVirtualRoot } from "../../../hooks/virtual-drive/VirtualRootContext.js";
+
+export function AboutSettings() {
+ const windowsManager = useWindowsManager();
+ const virtualRoot = useVirtualRoot();
+
+ return (<>
+
+
About ProzillaOS
+
ProzillaOS is a web-based operating system inspired by Ubuntu Linux and Windows made with React.js by Prozilla.
+
+
+
+
+
+ >);
+}
\ No newline at end of file
diff --git a/src/components/applications/settings/AppearanceSettings.jsx b/src/components/applications/settings/AppearanceSettings.jsx
new file mode 100644
index 0000000..be6fa9f
--- /dev/null
+++ b/src/components/applications/settings/AppearanceSettings.jsx
@@ -0,0 +1,42 @@
+import { useEffect, useState } from "react";
+import { SettingsManager } from "../../../features/settings/settings.js";
+import styles from "./Settings.module.css";
+import { useVirtualRoot } from "../../../hooks/virtual-drive/VirtualRootContext.js";
+import { useSettingsManager } from "../../../hooks/settings/SettingsContext.js";
+
+export function AppearanceSettings() {
+ const virtualRoot = useVirtualRoot();
+ const settingsManager = useSettingsManager();
+ const [wallpaper, setWallpaper] = useState(null);
+ const settings = settingsManager.get(SettingsManager.VIRTUAL_PATHS.desktop);
+
+ useEffect(() => {
+ settings.get("wallpaper", setWallpaper);
+ }, [settings]);
+
+ const onChange = (event) => {
+ const value = event.target.value;
+ settings.set("wallpaper", value);
+ };
+
+ return (<>
+
+ >);
+}
\ No newline at end of file
diff --git a/src/components/applications/settings/Settings.jsx b/src/components/applications/settings/Settings.jsx
index a2828e9..055d8f0 100644
--- a/src/components/applications/settings/Settings.jsx
+++ b/src/components/applications/settings/Settings.jsx
@@ -1,168 +1,47 @@
-import { useEffect, useState } from "react";
import styles from "./Settings.module.css";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faCircleInfo, faHardDrive, faPalette } from "@fortawesome/free-solid-svg-icons";
-import { useVirtualRoot } from "../../../hooks/virtual-drive/VirtualRootContext.js";
-import { useSettings } from "../../../hooks/settings/SettingsContext.js";
-import { SettingsManager } from "../../../features/settings/settings.js";
-import { VirtualRoot } from "../../../features/virtual-drive/virtual-root.js";
-import { StorageManager } from "../../../features/storage/storage.js";
-import { round } from "../../../features/math/round.js";
-import { Button } from "../../utils/Button.jsx";
-import { ProgressBar } from "../../utils/ProgressBar.jsx";
import utilStyles from "../../../styles/utils.module.css";
-import { useWindowsManager } from "../../../hooks/windows/WindowsManagerContext.js";
-import Vector2 from "../../../features/math/vector2.js";
+import { Tab, TabList, TabPanel, Tabs } from "react-tabs";
+import { AppearanceSettings } from "./AppearanceSettings.jsx";
+import { AboutSettings } from "./AboutSettings.jsx";
+import { StorageTab } from "./StorageSettings.jsx";
/**
- * @param {object} props
- * @param {VirtualRoot} props.virtualRoot
- * @param {SettingsManager} props.settingsManager
- */
-function AppearanceTab({ virtualRoot, settingsManager }) {
- const [wallpaper, setWallpaper] = useState(null);
- const settings = settingsManager.get(SettingsManager.VIRTUAL_PATHS.desktop);
-
- useEffect(() => {
- settings.get("wallpaper", setWallpaper);
- }, [settings]);
-
- const onChange = (event) => {
- const value = event.target.value;
- settings.set("wallpaper", value);
- };
-
- return (<>
-
- >);
-}
-
-/**
- * @param {object} root
- * @param {VirtualRoot} root.virtualRoot
- */
-function StorageTab({ virtualRoot }) {
- const maxBytes = StorageManager.MAX_BYTES;
- const usedBytes = StorageManager.getByteSize(virtualRoot.toString());
-
- const maxKB = StorageManager.byteToKilobyte(maxBytes);
- const usedKB = StorageManager.byteToKilobyte(usedBytes);
- const freeKB = maxKB - usedKB;
-
- return (<>
-
-
Virtual Drive ({round(maxKB, 1)} KB)
-
-
- {round(usedKB, 1)} KB used
- {round(freeKB, 1)} KB free
-
-
-
-
Manage data
-
-
- >);
-}
-
-function AboutTab({ windowsManager, virtualRoot }) {
- return (<>
-
-
About ProzillaOS
-
ProzillaOS is a web-based operating system inspired by Ubuntu Linux and Windows made with React.js by Prozilla.
-
-
-
-
-
- >);
-}
-
-/**
- * @param {number} param0
+ * @param {object} props
+ * @param {number} props.initialTabIndex
*/
export function Settings({ initialTabIndex }) {
- const [tabIndex, setTabIndex] = useState(initialTabIndex ?? 0);
- const virtualRoot = useVirtualRoot();
- const settingsManager = useSettings();
- const windowsManager = useWindowsManager();
-
- const getClassName = (index) => {
- const classNames = [styles["Tab-button"]];
-
- if (index === tabIndex)
- classNames.push(styles["Active-tab"]);
-
- return classNames.join(" ");
- };
-
return (
-
-
-
-
-
-
-
- {tabIndex === 0
- ?
- : tabIndex === 1
- ?
- : tabIndex === 2
- ?
- : null
- }
-
-
+
+
+
+
+
+
+
+
+
+
+
+
);
}
\ No newline at end of file
diff --git a/src/components/applications/settings/Settings.module.css b/src/components/applications/settings/Settings.module.css
index 8c167b8..4be41c2 100644
--- a/src/components/applications/settings/Settings.module.css
+++ b/src/components/applications/settings/Settings.module.css
@@ -17,6 +17,7 @@
height: 100%;
max-width: 50%;
padding: 0.5rem;
+ margin: 0;
background-color: var(--background-color-ba);
resize: horizontal;
overflow: hidden;
@@ -27,13 +28,10 @@
gap: 0.5rem;
align-items: center;
width: 100%;
+ min-width: fit-content;
padding: 0.75rem;
- background: none;
- border: none;
border-radius: 0.5rem;
- outline: none;
- cursor: pointer;
- transition: background-color 100ms ease-in-out;
+ font-size: 0.875rem;
}
.Tab-button.Active-tab {
@@ -64,6 +62,10 @@
overflow: auto;
}
+.Tab-panel:not(.Active-panel) {
+ display: none;
+}
+
.Option {
display: flex;
flex-direction: column;
@@ -100,14 +102,20 @@
height: 0;
}
+.Image-select > input:hover + img,
+.Image-select > input:focus-visible + img {
+ filter: brightness(110%);
+}
+
.Image-select > input:checked + img {
- outline: 0.25rem solid var(--foreground-color-a);
+ outline: 0.25em solid var(--foreground-color-a);
}
.Image-select > img {
width: 100%;
height: 100%;
border-radius: 0.5rem;
+ transition: filter 100ms ease-in-out;
cursor: pointer;
}
@@ -115,7 +123,7 @@
display: flex;
gap: 1rem;
flex-wrap: wrap;
- margin-bottom: 0.75rem;
+ margin: 0.75rem 0;
}
.Button-group .Button {
diff --git a/src/components/applications/settings/StorageSettings.jsx b/src/components/applications/settings/StorageSettings.jsx
new file mode 100644
index 0000000..ad04296
--- /dev/null
+++ b/src/components/applications/settings/StorageSettings.jsx
@@ -0,0 +1,38 @@
+import styles from "./Settings.module.css";
+import utilStyles from "../../../styles/utils.module.css";
+import { round } from "../../../features/math/round.js";
+import { ProgressBar } from "../../utils/ProgressBar.jsx";
+import { Button } from "../../utils/Button.jsx";
+import { useVirtualRoot } from "../../../hooks/virtual-drive/VirtualRootContext.js";
+import { StorageManager } from "../../../features/storage/storage.js";
+
+export function StorageTab() {
+ const virtualRoot = useVirtualRoot();
+
+ const maxBytes = StorageManager.MAX_BYTES;
+ const usedBytes = StorageManager.getByteSize(virtualRoot.toString());
+
+ const maxKB = StorageManager.byteToKilobyte(maxBytes);
+ const usedKB = StorageManager.byteToKilobyte(usedBytes);
+ const freeKB = maxKB - usedKB;
+
+ return (<>
+
+
Virtual Drive ({round(maxKB, 1)} KB)
+
+
+ {round(usedKB, 1)} KB used
+ {round(freeKB, 1)} KB free
+
+
+
+
Manage data
+
+
+ >);
+}
\ No newline at end of file
diff --git a/src/components/desktop/Desktop.jsx b/src/components/desktop/Desktop.jsx
index f6ce0e5..2ee0278 100644
--- a/src/components/desktop/Desktop.jsx
+++ b/src/components/desktop/Desktop.jsx
@@ -1,6 +1,6 @@
import { useState } from "react";
import { SettingsManager } from "../../features/settings/settings.js";
-import { useSettings } from "../../hooks/settings/SettingsContext.js";
+import { useSettingsManager } from "../../hooks/settings/SettingsContext.js";
import styles from "./Desktop.module.css";
import { useEffect } from "react";
import { useModals } from "../../hooks/modals/Modals.js";
@@ -9,7 +9,7 @@ import { useWindowsManager } from "../../hooks/windows/WindowsManagerContext.js"
import { useContextMenu } from "../../hooks/modals/ContextMenu.js";
export function Desktop() {
- const settingsManager = useSettings();
+ const settingsManager = useSettingsManager();
const [wallpaper, setWallpaper] = useState(null);
const [modalsManager, modals] = useModals();
const windowsManager = useWindowsManager();
diff --git a/src/hooks/settings/SettingsContext.js b/src/hooks/settings/SettingsContext.js
index cc02b3a..126bd7a 100644
--- a/src/hooks/settings/SettingsContext.js
+++ b/src/hooks/settings/SettingsContext.js
@@ -10,7 +10,7 @@ const SettingsContext = createContext();
* @param props.children
* @returns {import("react").Provider}
*/
-export function SettingsProvider({ children }) {
+export function SettingsManagerProvider({ children }) {
const virtualRoot = useVirtualRoot();
const settingsManager = new SettingsManager(virtualRoot);
@@ -24,6 +24,6 @@ export function SettingsProvider({ children }) {
/**
* @returns {SettingsManager}
*/
-export function useSettings() {
+export function useSettingsManager() {
return useContext(SettingsContext);
}
\ No newline at end of file
diff --git a/src/styles/global.css b/src/styles/global.css
index fa0076d..25e9890 100644
--- a/src/styles/global.css
+++ b/src/styles/global.css
@@ -87,7 +87,7 @@ h4 { font-size: 1.4em; }
h5 { font-size: 1.2em; }
h6 { font-size: 1em; }
-button {
+button, li[data-rttab="true"] {
margin: 0;
border: none;
outline: none;