Added storage tab to settings app
This commit is contained in:
parent
9c1074061e
commit
36e6d90276
4 changed files with 109 additions and 7 deletions
|
|
@ -1,12 +1,13 @@
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import styles from "./Settings.module.css";
|
import styles from "./Settings.module.css";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import { faPalette } from "@fortawesome/free-solid-svg-icons";
|
import { faHardDrive, faPalette } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { useVirtualRoot } from "../../../hooks/virtual-drive/VirtualRootContext.js";
|
import { useVirtualRoot } from "../../../hooks/virtual-drive/VirtualRootContext.js";
|
||||||
import { useSettings } from "../../../hooks/settings/SettingsContext.js";
|
import { useSettings } from "../../../hooks/settings/SettingsContext.js";
|
||||||
import { SettingsManager } from "../../../features/settings/settings.js";
|
import { SettingsManager } from "../../../features/settings/settings.js";
|
||||||
|
|
||||||
import { VirtualRoot } from "../../../features/virtual-drive/virtual-root.js";
|
import { VirtualRoot } from "../../../features/virtual-drive/virtual-root.js";
|
||||||
|
import { StorageManager } from "../../../features/storage/storage.js";
|
||||||
|
import { round } from "../../../features/math/round.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {object} props
|
* @param {object} props
|
||||||
|
|
@ -26,9 +27,9 @@ function AppearanceTab({ virtualRoot, settingsManager }) {
|
||||||
settings.set("wallpaper", value);
|
settings.set("wallpaper", value);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (<>
|
||||||
<div className={styles["Option"]}>
|
<div className={styles["Option"]}>
|
||||||
<p>Wallpaper</p>
|
<p className={styles["Label"]}>Wallpaper</p>
|
||||||
<div className={styles["Input"]}>
|
<div className={styles["Input"]}>
|
||||||
{virtualRoot.navigate("~/Images")?.getFiles()?.map(({ name, id, source }) =>
|
{virtualRoot.navigate("~/Images")?.getFiles()?.map(({ name, id, source }) =>
|
||||||
<label className={styles["Image-select"]} key={id}>
|
<label className={styles["Image-select"]} key={id}>
|
||||||
|
|
@ -38,7 +39,31 @@ function AppearanceTab({ virtualRoot, settingsManager }) {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
</>);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 (<>
|
||||||
|
<div className={styles["Option"]}>
|
||||||
|
<p className={styles["Label"]}>Virtual Drive ({round(maxKB, 1)} KB)</p>
|
||||||
|
<p>{round(usedKB, 1)} KB used - {round(freeKB, 1)} KB free</p>
|
||||||
|
</div>
|
||||||
|
<div className={styles["Option"]}>
|
||||||
|
<p className={styles["Label"]}>Manage data</p>
|
||||||
|
<button title="Reset" className={`${styles.Button} ${styles["Button-red"]}`}>Reset</button>
|
||||||
|
</div>
|
||||||
|
</>);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Settings() {
|
export function Settings() {
|
||||||
|
|
@ -49,15 +74,21 @@ export function Settings() {
|
||||||
return (
|
return (
|
||||||
<div className={styles.Container}>
|
<div className={styles.Container}>
|
||||||
<div className={styles.Tabs}>
|
<div className={styles.Tabs}>
|
||||||
<button title="Home" className={styles["Tab-button"]} onClick={() => { setTabIndex(0); }}>
|
<button title="Appearance" className={styles["Tab-button"]} onClick={() => { setTabIndex(0); }}>
|
||||||
<FontAwesomeIcon icon={faPalette}/>
|
<FontAwesomeIcon icon={faPalette}/>
|
||||||
Appearance
|
Appearance
|
||||||
</button>
|
</button>
|
||||||
|
<button title="Storage" className={styles["Tab-button"]} onClick={() => { setTabIndex(1); }}>
|
||||||
|
<FontAwesomeIcon icon={faHardDrive}/>
|
||||||
|
Storage
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles["Tab-panel"]}>
|
<div className={styles["Tab-panel"]}>
|
||||||
{tabIndex === 0
|
{tabIndex === 0
|
||||||
? <AppearanceTab virtualRoot={virtualRoot} settingsManager={settingsManager}/>
|
? <AppearanceTab virtualRoot={virtualRoot} settingsManager={settingsManager}/>
|
||||||
: null
|
: tabIndex === 1
|
||||||
|
? <StorageTab virtualRoot={virtualRoot}/>
|
||||||
|
: null
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
flex-direction: column;
|
||||||
align-content: flex-start;
|
align-content: flex-start;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding: 0.5rem 1rem;
|
padding: 0.5rem 1rem;
|
||||||
|
|
@ -60,6 +61,14 @@
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.Option > .Label {
|
||||||
|
color: var(--foreground-color-a);
|
||||||
|
}
|
||||||
|
|
||||||
|
.Option > p {
|
||||||
|
color: var(--foreground-color-c);
|
||||||
|
}
|
||||||
|
|
||||||
.Input {
|
.Input {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
|
|
@ -86,4 +95,31 @@
|
||||||
height: 100%;
|
height: 100%;
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Button {
|
||||||
|
--hover-color: var(--background-color-b);
|
||||||
|
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
color: var(--foreground-color-a);
|
||||||
|
background-color: var(--background-color-a);
|
||||||
|
border: none;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
outline: none;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0.05rem;
|
||||||
|
transition: background-color 100ms ease-in-out;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Button:hover, .Button:focus {
|
||||||
|
background-color: var(--hover-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.Button-red {
|
||||||
|
--hover-color: var(--red-b);
|
||||||
|
|
||||||
|
color: var(--background-color-a);
|
||||||
|
background-color: var(--red-a);
|
||||||
}
|
}
|
||||||
9
src/features/math/round.js
Normal file
9
src/features/math/round.js
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
/**
|
||||||
|
* @param {number} value
|
||||||
|
* @param {number} precision
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
export function round(value, precision) {
|
||||||
|
const multiplier = Math.pow(10, precision || 0);
|
||||||
|
return Math.round(value * multiplier) / multiplier;
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,18 @@
|
||||||
export class StorageManager {
|
export class StorageManager {
|
||||||
|
static MAX_BYTES = 5_000_000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} key
|
||||||
|
* @param {string} value
|
||||||
|
*/
|
||||||
static store(key, value) {
|
static store(key, value) {
|
||||||
localStorage.setItem(key, value);
|
localStorage.setItem(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} key
|
||||||
|
* @returns {string | null}
|
||||||
|
*/
|
||||||
static load(key) {
|
static load(key) {
|
||||||
return localStorage.getItem(key);
|
return localStorage.getItem(key);
|
||||||
}
|
}
|
||||||
|
|
@ -10,4 +20,20 @@ export class StorageManager {
|
||||||
static clear() {
|
static clear() {
|
||||||
localStorage.clear();
|
localStorage.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} string
|
||||||
|
* @returns {number} bytes
|
||||||
|
*/
|
||||||
|
static getByteSize(string) {
|
||||||
|
return new Blob([string]).size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} bytes
|
||||||
|
* @returns {number} kilobytes
|
||||||
|
*/
|
||||||
|
static byteToKilobyte(bytes) {
|
||||||
|
return bytes / 1000;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in a new issue