Added settings feature
This commit is contained in:
parent
919afa3c92
commit
37a5248a6e
20 changed files with 361 additions and 20 deletions
4
public/config/desktop.xml
Normal file
4
public/config/desktop.xml
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<options>
|
||||||
|
<wallpaper>/media/wallpapers/Wallpaper1.png</wallpaper>
|
||||||
|
</options>
|
||||||
14
src/App.jsx
14
src/App.jsx
|
|
@ -3,16 +3,20 @@ import { Taskbar } from "./components/task-bar/TaskBar.jsx";
|
||||||
import { WindowsManagerProvider } from "./hooks/windows/WindowsManagerContext.js";
|
import { WindowsManagerProvider } from "./hooks/windows/WindowsManagerContext.js";
|
||||||
import { WindowsView } from "./components/windows/WindowsView.jsx";
|
import { WindowsView } from "./components/windows/WindowsView.jsx";
|
||||||
import { VirtualRootProvider } from "./hooks/virtual-drive/VirtualRootContext.js";
|
import { VirtualRootProvider } from "./hooks/virtual-drive/VirtualRootContext.js";
|
||||||
import { SETTINGS } from "./config/settings.js";
|
import { Desktop } from "./components/desktop/Desktop.jsx";
|
||||||
|
import { SettingsProvider } from "./hooks/settings/SettingsContext.js";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<VirtualRootProvider>
|
<VirtualRootProvider>
|
||||||
<WindowsManagerProvider>
|
<WindowsManagerProvider>
|
||||||
<div className={styles.App} style={{ backgroundImage: `url(${SETTINGS.wallpaper})` }}>
|
<SettingsProvider>
|
||||||
<Taskbar/>
|
<div className={styles.App}>
|
||||||
<WindowsView/>
|
<Taskbar/>
|
||||||
</div>
|
<WindowsView/>
|
||||||
|
<Desktop/>
|
||||||
|
</div>
|
||||||
|
</SettingsProvider>
|
||||||
</WindowsManagerProvider>
|
</WindowsManagerProvider>
|
||||||
</VirtualRootProvider>
|
</VirtualRootProvider>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,5 @@
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-size: cover;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ export function FileExplorer({ startPath }) {
|
||||||
const [currentDirectory, setCurrentDirectory] = useState(virtualRoot.navigate(startPath ?? "~"));
|
const [currentDirectory, setCurrentDirectory] = useState(virtualRoot.navigate(startPath ?? "~"));
|
||||||
const [path, setPath] = useState(currentDirectory.path);
|
const [path, setPath] = useState(currentDirectory.path);
|
||||||
const windowsManager = useWindowsManager();
|
const windowsManager = useWindowsManager();
|
||||||
|
const [showHidden] = useState(true);
|
||||||
|
|
||||||
const changeDirectory = (path, absolute = false) => {
|
const changeDirectory = (path, absolute = false) => {
|
||||||
const directory = absolute ? virtualRoot.navigate(path) : currentDirectory.navigate(path);
|
const directory = absolute ? virtualRoot.navigate(path) : currentDirectory.navigate(path);
|
||||||
|
|
@ -107,7 +108,7 @@ export function FileExplorer({ startPath }) {
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.Main}>
|
<div className={styles.Main}>
|
||||||
{currentDirectory.files.map((file, index) =>
|
{currentDirectory.getFiles(showHidden).map((file, index) =>
|
||||||
<button key={index} title={file.id} className={styles["File-button"]} onClick={(event) => {
|
<button key={index} title={file.id} className={styles["File-button"]} onClick={(event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
windowsManager.openFile(file);
|
windowsManager.openFile(file);
|
||||||
|
|
@ -116,7 +117,7 @@ export function FileExplorer({ startPath }) {
|
||||||
<p>{file.id}</p>
|
<p>{file.id}</p>
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
{currentDirectory.subFolders.map(({ name }, index) =>
|
{currentDirectory.getSubFolders(showHidden).map(({ name }, index) =>
|
||||||
<button key={index} title={name} className={styles["Folder-button"]} onClick={() => {
|
<button key={index} title={name} className={styles["Folder-button"]} onClick={() => {
|
||||||
changeDirectory(name);
|
changeDirectory(name);
|
||||||
}}>
|
}}>
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,7 @@
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
align-content: flex-start;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ export function TextEditor({ file, setTitle, close, mode }) {
|
||||||
if (currentFile == null)
|
if (currentFile == null)
|
||||||
return saveTextAs();
|
return saveTextAs();
|
||||||
|
|
||||||
currentFile.content = content;
|
currentFile.setContent(content);
|
||||||
onChange({ target: { value: content } });
|
onChange({ target: { value: content } });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
21
src/components/desktop/Desktop.jsx
Normal file
21
src/components/desktop/Desktop.jsx
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { useState } from "react";
|
||||||
|
import { SettingsManager } from "../../features/settings/settings.js";
|
||||||
|
import { useSettings } from "../../hooks/settings/SettingsContext.js";
|
||||||
|
import styles from "./Desktop.module.css";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
|
export function Desktop() {
|
||||||
|
const settingsManager = useSettings();
|
||||||
|
const [wallpaper, setWallpaper] = useState(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
const settings = settingsManager.get(SettingsManager.VIRTUAL_PATHS.desktop);
|
||||||
|
settings.get("wallpaper", setWallpaper);
|
||||||
|
})();
|
||||||
|
}, [settingsManager]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.Container} style={{ backgroundImage: `url(${wallpaper})` }}/>
|
||||||
|
);
|
||||||
|
}
|
||||||
10
src/components/desktop/Desktop.module.css
Normal file
10
src/components/desktop/Desktop.module.css
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
.Container {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: -1;
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
}
|
||||||
|
|
@ -11,9 +11,9 @@ export function WindowsView() {
|
||||||
return (<div>
|
return (<div>
|
||||||
{windows.sort((windowA, windowB) =>
|
{windows.sort((windowA, windowB) =>
|
||||||
windowA.lastInteraction - windowB.lastInteraction
|
windowA.lastInteraction - windowB.lastInteraction
|
||||||
).map(({ id, app, size, position, options }, index) =>
|
).map(({ id, app, size, position, options }) =>
|
||||||
<Window
|
<Window
|
||||||
onInteract={() => { windowsManager.focus(windows[index]); }}
|
onInteract={() => { windowsManager.focus(id); }}
|
||||||
id={id}
|
id={id}
|
||||||
key={id}
|
key={id}
|
||||||
app={app}
|
app={app}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
export const SETTINGS = {
|
|
||||||
wallpaper: "/media/wallpapers/Wallpaper1.png"
|
|
||||||
};
|
|
||||||
|
|
@ -51,6 +51,7 @@ export default class ApplicationsManager {
|
||||||
break;
|
break;
|
||||||
case "txt":
|
case "txt":
|
||||||
case "md":
|
case "md":
|
||||||
|
case "xml":
|
||||||
app = this.getApplication("text-editor");
|
app = this.getApplication("text-editor");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
160
src/features/settings/settings.js
Normal file
160
src/features/settings/settings.js
Normal file
|
|
@ -0,0 +1,160 @@
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
import { VirtualFile } from "../virtual-drive/virtual-file.js";
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
import { VirtualRoot } from "../virtual-drive/virtual-root.js";
|
||||||
|
|
||||||
|
export class Settings {
|
||||||
|
xmlDoc = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {VirtualRoot}
|
||||||
|
*/
|
||||||
|
#virtualRoot = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {VirtualRoot} virtualRoot
|
||||||
|
* @param {String} path
|
||||||
|
*/
|
||||||
|
constructor(virtualRoot, path) {
|
||||||
|
this.#virtualRoot = virtualRoot;
|
||||||
|
this.path = path;
|
||||||
|
this.file = this.#virtualRoot.navigate(this.path);
|
||||||
|
|
||||||
|
if (this.file == null) {
|
||||||
|
console.warn(`Unable to read settings from path: ${this.path}\nNo such file or directory.`);
|
||||||
|
return null;
|
||||||
|
} else if (!(this.file instanceof VirtualFile)) {
|
||||||
|
console.warn(`Unable to read settings from path: ${this.path}\nPath does not point to VirtualFile.`);
|
||||||
|
return null;
|
||||||
|
} else if (this.file.extension !== "xml") {
|
||||||
|
console.warn(`Unable to read settings from path: ${this.path}\nFile does not have extension "xml".`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the xml doc from the given path and assigns it to itself
|
||||||
|
* @returns {Promise<Settings>}
|
||||||
|
*/
|
||||||
|
async read() {
|
||||||
|
if (!this.file)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const text = await this.file.read();
|
||||||
|
|
||||||
|
if (!text)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const parser = new DOMParser();
|
||||||
|
const xmlDoc = parser.parseFromString(text, "text/xml");
|
||||||
|
|
||||||
|
this.xmlDoc = xmlDoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
async write() {
|
||||||
|
if (!this.file)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const serializer = new XMLSerializer();
|
||||||
|
const xmlString = serializer.serializeToString(this.xmlDoc);
|
||||||
|
|
||||||
|
this.file.setContent(xmlString);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if xml doc is missing
|
||||||
|
* @returns {Promise<Boolean>}
|
||||||
|
*/
|
||||||
|
async isMissingXmlDoc() {
|
||||||
|
if (this.xmlDoc == null)
|
||||||
|
await this.read();
|
||||||
|
|
||||||
|
return (this.xmlDoc == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @callback valueCallback
|
||||||
|
* @param {String} value
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a value by a given key if it exists or calls a callback function whenever the value changes
|
||||||
|
* @param {String} key
|
||||||
|
* @param {valueCallback} callback
|
||||||
|
* @returns {Promise<String|null>}
|
||||||
|
*/
|
||||||
|
async get(key, callback) {
|
||||||
|
if (await this.isMissingXmlDoc())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
let value = this.xmlDoc.getElementsByTagName(key)?.[0]?.textContent;
|
||||||
|
|
||||||
|
if (callback) {
|
||||||
|
callback(value);
|
||||||
|
|
||||||
|
this.file.on(VirtualFile.EVENT_NAMES.CONTENT_CHANGE, async () => {
|
||||||
|
await this.read();
|
||||||
|
const newValue = await this.get(key);
|
||||||
|
|
||||||
|
if (newValue !== value) {
|
||||||
|
callback(newValue);
|
||||||
|
value = newValue;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {String} key
|
||||||
|
* @param {String} value
|
||||||
|
*/
|
||||||
|
async set(key, value) {
|
||||||
|
if (await this.isMissingXmlDoc())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (this.xmlDoc.getElementsByTagName(key)?.[0])
|
||||||
|
this.xmlDoc.getElementsByTagName(key)[0].textContent = value;
|
||||||
|
|
||||||
|
await this.write();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SettingsManager {
|
||||||
|
/**
|
||||||
|
* @type {Object<String, String>}
|
||||||
|
*/
|
||||||
|
static VIRTUAL_PATHS = {
|
||||||
|
"desktop": "~/.config/desktop.xml"
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object<String, Settings>}
|
||||||
|
*/
|
||||||
|
#pathToSettings = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {VirtualRoot}
|
||||||
|
*/
|
||||||
|
#virtualRoot = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {VirtualRoot} virtualRoot
|
||||||
|
*/
|
||||||
|
constructor(virtualRoot) {
|
||||||
|
this.#virtualRoot = virtualRoot;
|
||||||
|
|
||||||
|
Object.values(SettingsManager.VIRTUAL_PATHS).forEach((path) => {
|
||||||
|
this.#pathToSettings[path] = new Settings(this.#virtualRoot, path);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {String} path
|
||||||
|
* @returns {Settings}
|
||||||
|
*/
|
||||||
|
get(path) {
|
||||||
|
return this.#pathToSettings[path];
|
||||||
|
}
|
||||||
|
}
|
||||||
49
src/features/utils/events.js
Normal file
49
src/features/utils/events.js
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
export class EventEmitter {
|
||||||
|
/**
|
||||||
|
* @type {Object<String, String>}
|
||||||
|
*/
|
||||||
|
static EVENT_NAMES = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object<String, Array<Function>>}
|
||||||
|
*/
|
||||||
|
#events = {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add event listener for an event
|
||||||
|
* @param {EVENT_NAMES} eventName
|
||||||
|
* @param {Function} callback
|
||||||
|
*/
|
||||||
|
on(eventName, callback) {
|
||||||
|
if (!this.#events[eventName]) {
|
||||||
|
this.#events[eventName] = [];
|
||||||
|
}
|
||||||
|
this.#events[eventName].push(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove event listener for an event
|
||||||
|
* @param {EVENT_NAMES} eventName
|
||||||
|
* @param {Function} callback
|
||||||
|
*/
|
||||||
|
off(eventName, callback) {
|
||||||
|
if (this.#events[eventName]) {
|
||||||
|
this.#events[eventName] = this.#events[eventName].filter(
|
||||||
|
(listener) => listener !== callback
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatch event
|
||||||
|
* @param {EVENT_NAMES} eventName
|
||||||
|
* @param {*} data
|
||||||
|
*/
|
||||||
|
emit(eventName, data) {
|
||||||
|
if (this.#events[eventName]) {
|
||||||
|
this.#events[eventName].forEach((listener) => {
|
||||||
|
listener(data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
|
import { EventEmitter } from "../utils/events.js";
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
import { VirtualRoot } from "./virtual-root.js";
|
import { VirtualRoot } from "./virtual-root.js";
|
||||||
|
|
||||||
export class VirtualBase {
|
export class VirtualBase extends EventEmitter {
|
||||||
/**
|
/**
|
||||||
* @param {String} name
|
* @param {String} name
|
||||||
*/
|
*/
|
||||||
constructor(name) {
|
constructor(name) {
|
||||||
|
super();
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,14 @@ import { VirtualBase } from "./virtual-base.js";
|
||||||
* A virtual file that can be stored inside a folder
|
* A virtual file that can be stored inside a folder
|
||||||
*/
|
*/
|
||||||
export class VirtualFile extends VirtualBase {
|
export class VirtualFile extends VirtualBase {
|
||||||
|
static NON_TEXT_EXTENSIONS = [
|
||||||
|
"png"
|
||||||
|
];
|
||||||
|
|
||||||
|
static EVENT_NAMES = {
|
||||||
|
CONTENT_CHANGE: "contentchange"
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {String} name
|
* @param {String} name
|
||||||
* @param {String=} extension
|
* @param {String=} extension
|
||||||
|
|
@ -29,6 +37,7 @@ export class VirtualFile extends VirtualBase {
|
||||||
setSource(source) {
|
setSource(source) {
|
||||||
this.source = source;
|
this.source = source;
|
||||||
this.content = null;
|
this.content = null;
|
||||||
|
this.emit(VirtualFile.EVENT_NAMES.CONTENT_CHANGE, this);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -40,6 +49,7 @@ export class VirtualFile extends VirtualBase {
|
||||||
setContent(content) {
|
setContent(content) {
|
||||||
this.content = content;
|
this.content = content;
|
||||||
this.source = null;
|
this.source = null;
|
||||||
|
this.emit(VirtualFile.EVENT_NAMES.CONTENT_CHANGE, this);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -49,4 +59,25 @@ export class VirtualFile extends VirtualBase {
|
||||||
|
|
||||||
return `${this.name}.${this.extension}`;
|
return `${this.name}.${this.extension}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {Promise<String|null>}
|
||||||
|
*/
|
||||||
|
async read() {
|
||||||
|
if (this.content != null)
|
||||||
|
return this.content;
|
||||||
|
|
||||||
|
const isText = !VirtualFile.NON_TEXT_EXTENSIONS.includes(this.extension);
|
||||||
|
|
||||||
|
if (!isText) {
|
||||||
|
return this.source;
|
||||||
|
}
|
||||||
|
|
||||||
|
return await fetch(this.source).then((response) =>
|
||||||
|
response.text()
|
||||||
|
).catch((error) => {
|
||||||
|
console.error(`Error while reading file with id "${this.id}":`, error);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -268,4 +268,28 @@ export class VirtualFolder extends VirtualBase {
|
||||||
item.delete();
|
item.delete();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Boolean=false} showHidden
|
||||||
|
*/
|
||||||
|
getSubFolders(showHidden = false) {
|
||||||
|
if (showHidden)
|
||||||
|
return this.subFolders;
|
||||||
|
|
||||||
|
return this.subFolders.filter(({ name }) =>
|
||||||
|
!name.startsWith(".")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Boolean=false} showHidden
|
||||||
|
*/
|
||||||
|
getFiles(showHidden = false) {
|
||||||
|
if (showHidden)
|
||||||
|
return this.files;
|
||||||
|
|
||||||
|
return this.files.filter(({ name }) =>
|
||||||
|
!name.startsWith(".")
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -74,8 +74,17 @@ export default class WindowsManager {
|
||||||
/**
|
/**
|
||||||
* @param {Object} window
|
* @param {Object} window
|
||||||
*/
|
*/
|
||||||
focus(window) {
|
focus(windowId) {
|
||||||
|
windowId = windowId.toString();
|
||||||
|
|
||||||
|
if (!this.windowIds.includes(windowId)) {
|
||||||
|
console.log(`Failed to focus window ${windowId}: window not found`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const window = this.windows[windowId];
|
||||||
window.lastInteraction = new Date().valueOf();
|
window.lastInteraction = new Date().valueOf();
|
||||||
|
|
||||||
this.updateWindows(this.windows);
|
this.updateWindows(this.windows);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
27
src/hooks/settings/SettingsContext.js
Normal file
27
src/hooks/settings/SettingsContext.js
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { createContext, useContext } from "react";
|
||||||
|
import { SettingsManager } from "../../features/settings/settings.js";
|
||||||
|
import { useVirtualRoot } from "../virtual-drive/VirtualRootContext.js";
|
||||||
|
|
||||||
|
const SettingsContext = createContext();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note: needs to be inside a virtual root provider
|
||||||
|
* @returns {React.Provider<SettingsManager>}
|
||||||
|
*/
|
||||||
|
export function SettingsProvider({ children }) {
|
||||||
|
const virtualRoot = useVirtualRoot();
|
||||||
|
const settingsManager = new SettingsManager(virtualRoot);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SettingsContext.Provider value={settingsManager}>
|
||||||
|
{children}
|
||||||
|
</SettingsContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {SettingsManager}
|
||||||
|
*/
|
||||||
|
export function useSettings() {
|
||||||
|
return useContext(SettingsContext);
|
||||||
|
}
|
||||||
|
|
@ -57,15 +57,12 @@ export function useScrollWithShadow(options) {
|
||||||
if (!element)
|
if (!element)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
console.log(element);
|
|
||||||
|
|
||||||
setScrollStart(horizontal ? element.scrollLeft : element.scrollTop);
|
setScrollStart(horizontal ? element.scrollLeft : element.scrollTop);
|
||||||
setScrollLength(horizontal ? element.scrollWidth : element.scrollHeight);
|
setScrollLength(horizontal ? element.scrollWidth : element.scrollHeight);
|
||||||
setClientLength(horizontal ? element.clientWidth : element.clientHeight);
|
setClientLength(horizontal ? element.clientWidth : element.clientHeight);
|
||||||
}, [horizontal]);
|
}, [horizontal]);
|
||||||
|
|
||||||
const onUpdate = (event) => {
|
const onUpdate = (event) => {
|
||||||
console.log(event);
|
|
||||||
updateValues(event.target);
|
updateValues(event.target);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -75,7 +72,6 @@ export function useScrollWithShadow(options) {
|
||||||
};
|
};
|
||||||
|
|
||||||
if (ref.current && !initiated) {
|
if (ref.current && !initiated) {
|
||||||
console.log(ref.current);
|
|
||||||
setInitiated(true);
|
setInitiated(true);
|
||||||
updateValues(ref.current);
|
updateValues(ref.current);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,11 @@ function initVirtualRoot(virtualRoot) {
|
||||||
virtualRoot.createFolder("home", (folder) => {
|
virtualRoot.createFolder("home", (folder) => {
|
||||||
folder.createFolder("prozilla-os", (folder) => {
|
folder.createFolder("prozilla-os", (folder) => {
|
||||||
folder.setAlias("~")
|
folder.setAlias("~")
|
||||||
|
.createFolder(".config", (folder) => {
|
||||||
|
folder.createFile("desktop", "xml", (file) => {
|
||||||
|
file.setSource("/config/desktop.xml");
|
||||||
|
});
|
||||||
|
})
|
||||||
.createFolder("Images", (folder) => {
|
.createFolder("Images", (folder) => {
|
||||||
folder.createFile("Wallpaper1", "png", (file) => {
|
folder.createFile("Wallpaper1", "png", (file) => {
|
||||||
file.setSource("/media/wallpapers/Wallpaper1.png")
|
file.setSource("/media/wallpapers/Wallpaper1.png")
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue