Added themes
This commit is contained in:
parent
2ede410bec
commit
e74765e2c8
21 changed files with 1193 additions and 380 deletions
|
|
@ -53,7 +53,7 @@ export default tseslint.config(
|
|||
}
|
||||
],
|
||||
"comma-spacing": "off",
|
||||
"@typescript-eslint/comma-spacing": "error",
|
||||
"@typescript-eslint/comma-spacing": "warn",
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
|
|
|
|||
1339
package-lock.json
generated
1339
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -10,7 +10,6 @@
|
|||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject",
|
||||
"predeploy": "npm run build",
|
||||
"deploy": "sh deploy.sh"
|
||||
},
|
||||
|
|
@ -43,6 +42,7 @@
|
|||
"devDependencies": {
|
||||
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
||||
"@eslint/js": "^9.2.0",
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/react-syntax-highlighter": "^15.5.13",
|
||||
"@types/webpack-env": "^1.18.4",
|
||||
"@typescript-eslint/eslint-plugin": "^7.8.0",
|
||||
|
|
@ -51,6 +51,8 @@
|
|||
"eslint-plugin-jsdoc": "^46.4.6",
|
||||
"eslint-plugin-react": "^7.34.1",
|
||||
"gh-pages": "^5.0.0",
|
||||
"jest": "^27.5.1",
|
||||
"ts-jest": "^29.1.2",
|
||||
"typescript": "^4.9.5",
|
||||
"typescript-eslint": "^7.8.0"
|
||||
},
|
||||
|
|
|
|||
3
public/config/theme.xml
Normal file
3
public/config/theme.xml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<options>
|
||||
<theme>0</theme>
|
||||
</options>
|
||||
|
|
@ -11,4 +11,4 @@
|
|||
|
||||
.App > * {
|
||||
pointer-events: auto;
|
||||
}
|
||||
}
|
||||
23
src/App.tsx
23
src/App.tsx
|
|
@ -6,11 +6,12 @@ import { VirtualRootProvider } from "./hooks/virtual-drive/virtualRootContext";
|
|||
import { Desktop } from "./components/desktop/Desktop";
|
||||
import { SettingsManagerProvider } from "./hooks/settings/settingsManagerContext";
|
||||
import { ModalsView } from "./components/modals/ModalsView";
|
||||
import { FC, useEffect } from "react";
|
||||
import { ReactElement, useEffect } from "react";
|
||||
import { ZIndexManagerProvider } from "./hooks/z-index/zIndexManagerContext";
|
||||
import { ModalsManagerProvider } from "./hooks/modals/modalsManagerContext";
|
||||
import { ThemeProvider } from "./hooks/themes/themes";
|
||||
|
||||
const App: FC = () => {
|
||||
export default function App(): ReactElement {
|
||||
useEffect(() => {
|
||||
const onContextMenu = (event: Event) => {
|
||||
event.preventDefault();
|
||||
|
|
@ -29,18 +30,18 @@ const App: FC = () => {
|
|||
<WindowsManagerProvider>
|
||||
<ModalsManagerProvider>
|
||||
<SettingsManagerProvider>
|
||||
<div className={styles.App}>
|
||||
<Taskbar/>
|
||||
<WindowsView/>
|
||||
<ModalsView/>
|
||||
<Desktop/>
|
||||
</div>
|
||||
<ThemeProvider>
|
||||
<div className={styles.App}>
|
||||
<Taskbar/>
|
||||
<WindowsView/>
|
||||
<ModalsView/>
|
||||
<Desktop/>
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
</SettingsManagerProvider>
|
||||
</ModalsManagerProvider>
|
||||
</WindowsManagerProvider>
|
||||
</ZIndexManagerProvider>
|
||||
</VirtualRootProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
};
|
||||
|
|
@ -154,7 +154,7 @@
|
|||
}
|
||||
|
||||
.Button-red {
|
||||
--text-color: var(--background-color-a) !important;
|
||||
--text-color: var(--dark-grey-b) !important;
|
||||
--normal-color: var(--red-a) !important;
|
||||
--hover-color: var(--red-b) !important;
|
||||
}
|
||||
|
|
@ -241,4 +241,26 @@
|
|||
width: inherit;
|
||||
height: inherit;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.Dropdown {
|
||||
width: auto;
|
||||
max-width: calc(60% - var(--gap));
|
||||
padding: 0.5rem 1rem;
|
||||
color: var(--text-color);
|
||||
background-color: var(--background-color-a);
|
||||
border: none;
|
||||
border-radius: 0.5rem;
|
||||
outline: none;
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
.Dropdown > * {
|
||||
color: inherit;
|
||||
background-color: inherit;
|
||||
border: none;
|
||||
border-radius: 0.5rem;
|
||||
outline: none;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
}
|
||||
|
|
@ -9,6 +9,13 @@ import { StorageTab } from "./tabs/StorageSettings";
|
|||
import { AppsSettings } from "./tabs/AppsSettings";
|
||||
import { WindowProps } from "../../windows/WindowView";
|
||||
|
||||
export const TABS = {
|
||||
APPS: 0,
|
||||
APPEARANCE: 1,
|
||||
STORAGE: 2,
|
||||
ABOUT: 3,
|
||||
};
|
||||
|
||||
interface SettingsProps extends WindowProps {
|
||||
tab?: number;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,24 +13,43 @@ import { DEFAULT_FILE_SELECTOR_SIZE } from "../../../../config/modals.config";
|
|||
import { IMAGE_FORMATS } from "../../../../config/apps/mediaViewer.config";
|
||||
import { VirtualFile } from "../../../../features/virtual-drive/file/virtualFile";
|
||||
import { VirtualFolder } from "../../../../features/virtual-drive/folder/virtualFolder";
|
||||
import { THEMES } from "../../../../hooks/themes/themes";
|
||||
|
||||
export function AppearanceSettings() {
|
||||
const virtualRoot = useVirtualRoot();
|
||||
const settingsManager = useSettingsManager();
|
||||
const [theme, setTheme] = useState(0);
|
||||
const [wallpaper, setWallpaper] = useState<string>(null);
|
||||
const settings = settingsManager.get(SettingsManager.VIRTUAL_PATHS.desktop);
|
||||
const desktopSettings = settingsManager.get(SettingsManager.VIRTUAL_PATHS.desktop);
|
||||
const themeSettings = settingsManager.get(SettingsManager.VIRTUAL_PATHS.theme);
|
||||
const { openWindowedModal } = useWindowedModal();
|
||||
|
||||
useEffect(() => {
|
||||
void settings.get("wallpaper", setWallpaper);
|
||||
}, [settings]);
|
||||
void desktopSettings.get("wallpaper", setWallpaper);
|
||||
void themeSettings.get("theme", (value: string) => { setTheme(parseInt(value)); });
|
||||
}, [desktopSettings, themeSettings]);
|
||||
|
||||
const onChange = (event: Event) => {
|
||||
const onWallpaperChange = (event: Event) => {
|
||||
const value = (event.target as HTMLInputElement).value;
|
||||
void settings.set("wallpaper", value);
|
||||
void desktopSettings.set("wallpaper", value);
|
||||
};
|
||||
|
||||
const onThemeChange = (event: Event) => {
|
||||
const value = (event.target as HTMLInputElement).value;
|
||||
void themeSettings.set("theme", value);
|
||||
};
|
||||
|
||||
return (<>
|
||||
<div className={styles["Option"]}>
|
||||
<p className={styles["Label"]}>Theme</p>
|
||||
<div className={styles["Input"]}>
|
||||
<select className={styles["Dropdown"]} aria-label="theme" value={theme} onChange={onThemeChange as unknown as ChangeEventHandler}>
|
||||
{Object.entries(THEMES).map(([key, value]) =>
|
||||
<option key={key} value={key}>{value}</option>
|
||||
)}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles["Option"]}>
|
||||
<p className={styles["Label"]}>Wallpaper</p>
|
||||
<Button
|
||||
|
|
@ -42,7 +61,7 @@ export function AppearanceSettings() {
|
|||
type={SELECTOR_MODE.SINGLE}
|
||||
allowedFormats={IMAGE_FORMATS}
|
||||
onFinish={(file: VirtualFile) => {
|
||||
void settings.set("wallpaper", file.source);
|
||||
void desktopSettings.set("wallpaper", file.source);
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -59,7 +78,7 @@ export function AppearanceSettings() {
|
|||
value={source}
|
||||
aria-label="Wallpaper image"
|
||||
checked={source === wallpaper}
|
||||
onChange={onChange as unknown as ChangeEventHandler}
|
||||
onChange={onWallpaperChange as unknown as ChangeEventHandler}
|
||||
tabIndex={0}
|
||||
/>
|
||||
<img src={source} alt={id} draggable="false"/>
|
||||
|
|
|
|||
|
|
@ -38,6 +38,10 @@
|
|||
text-shadow: 0.1rem 0.1rem 0.2rem hsla(var(--background-color-a-hsl), 75%);
|
||||
}
|
||||
|
||||
.Item p {
|
||||
color: var(--white-a);
|
||||
}
|
||||
|
||||
.Item svg {
|
||||
filter: drop-shadow(0.1rem 0.1rem 0.2rem hsla(var(--background-color-a-hsl), 50%));
|
||||
}
|
||||
|
|
@ -25,6 +25,7 @@ import ModalsManager from "../../features/modals/modalsManager";
|
|||
import { VirtualFolder } from "../../features/virtual-drive/folder/virtualFolder";
|
||||
import { VirtualFolderLink } from "../../features/virtual-drive/folder/virtualFolderLink";
|
||||
import { VirtualFile } from "../../features/virtual-drive/file/virtualFile";
|
||||
import { TABS } from "../apps/settings/Settings";
|
||||
|
||||
export const Desktop = memo(() => {
|
||||
const settingsManager = useSettingsManager();
|
||||
|
|
@ -58,7 +59,7 @@ export const Desktop = memo(() => {
|
|||
reloadViewport();
|
||||
}}/>
|
||||
<ClickAction label="Change appearance" icon={faPaintBrush} onTrigger={() => {
|
||||
windowsManager.open("settings", { tab: 0 });
|
||||
windowsManager.open("settings", { tab: TABS.APPEARANCE });
|
||||
}}/>
|
||||
<Divider/>
|
||||
<ClickAction label={`Open in ${APP_NAMES.FILE_EXPLORER}`} icon={APP_ICONS.FILE_EXPLORER} onTrigger={() => {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
display: flex;
|
||||
min-width: 16rem;
|
||||
max-width: 32rem;
|
||||
background-color: rgba(25, 25, 25, 75%);
|
||||
background-color: hsla(var(--background-color-c-hsl), 75%);
|
||||
border-top-left-radius: 0.5rem;
|
||||
border-top-right-radius: 0.5rem;
|
||||
border-bottom-right-radius: 0.5rem;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
min-width: 13rem;
|
||||
max-width: 19rem;
|
||||
padding: 0.5rem;
|
||||
background-color: rgba(25, 25, 25, 75%);
|
||||
background-color: hsla(var(--background-color-c-hsl), 75%);
|
||||
border-top-left-radius: 0.5rem;
|
||||
border-top-right-radius: 0.5rem;
|
||||
border-bottom-right-radius: 0.5rem;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
.Container-inner {
|
||||
opacity: 1;
|
||||
display: flex;
|
||||
background-color: rgba(25, 25, 25, 75%);
|
||||
background-color: hsla(var(--background-color-c-hsl), 75%);
|
||||
border-top-left-radius: 0.5rem;
|
||||
border-top-right-radius: 0.5rem;
|
||||
border-bottom-left-radius: 0.5rem;
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ export function generateUrl(options: { appId: string; fullscreen: boolean; }) {
|
|||
return baseUrl;
|
||||
|
||||
const { appId, fullscreen, ...extraOptions } = options;
|
||||
const params = new URLSearchParams();
|
||||
const params: URLSearchParams & { size?: number } = new URLSearchParams();
|
||||
|
||||
if (appId)
|
||||
params.set("app", appId);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ export class SettingsManager {
|
|||
desktop: "~/.config/desktop.xml",
|
||||
taskbar: "~/.config/taskbar.xml",
|
||||
apps: "~/.config/apps.xml",
|
||||
theme: "~/.config/theme.xml"
|
||||
};
|
||||
|
||||
#pathToSettings: { [s: string]: Settings; } = {};
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ export function loadDefaultData(virtualRoot: VirtualRoot) {
|
|||
file.setSource("/config/taskbar.xml");
|
||||
}).createFile("apps", "xml", (file) => {
|
||||
file.setSource("/config/apps.xml");
|
||||
}).createFile("theme", "xml", (file) => {
|
||||
file.setSource("/config/apps.xml");
|
||||
});
|
||||
})
|
||||
.createFolder("Pictures", (folder) => {
|
||||
|
|
@ -131,6 +133,8 @@ export function loadDefaultData(virtualRoot: VirtualRoot) {
|
|||
file.setSource(`${process.env.PUBLIC_URL}/config/desktop.xml`);
|
||||
}).createFile("taskbar", "xml", (file) => {
|
||||
file.setSource(`${process.env.PUBLIC_URL}/config/taskbar.xml`);
|
||||
}).createFile("theme", "xml", (file) => {
|
||||
file.setSource(`${process.env.PUBLIC_URL}/config/theme.xml`);
|
||||
});
|
||||
}).createFolder("documents", (folder) => {
|
||||
folder.createFile("info", "md", (file) => {
|
||||
|
|
|
|||
31
src/hooks/themes/themes.tsx
Normal file
31
src/hooks/themes/themes.tsx
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import { ReactElement, useEffect, useState } from "react";
|
||||
import { useSettingsManager } from "../settings/settingsManagerContext";
|
||||
import { SettingsManager } from "../../features/settings/settingsManager";
|
||||
|
||||
export const THEMES = {
|
||||
0: "Dark",
|
||||
1: "Light",
|
||||
4: "Muted",
|
||||
2: "Cherry",
|
||||
3: "Mango",
|
||||
5: "Aqua",
|
||||
6: "Grape"
|
||||
};
|
||||
|
||||
interface ThemeProviderProps {
|
||||
children: ReactElement;
|
||||
}
|
||||
|
||||
export function ThemeProvider({ children }: ThemeProviderProps): ReactElement {
|
||||
const [theme, setTheme] = useState(0);
|
||||
const settingsManager = useSettingsManager();
|
||||
const themeSettings = settingsManager.get(SettingsManager.VIRTUAL_PATHS.theme);
|
||||
|
||||
useEffect(() => {
|
||||
void themeSettings.get("theme", (value: string) => { setTheme(parseInt(value)); });
|
||||
}, [themeSettings]);
|
||||
|
||||
return <div className={`${THEMES[theme]}-theme`}>
|
||||
{children}
|
||||
</div>;
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
@import "./global/variables.css";
|
||||
@import "./global/fonts.css";
|
||||
@import "./global/themes.css";
|
||||
@import "./global/scrollbar.css";
|
||||
|
||||
html, body, #root {
|
||||
|
|
|
|||
70
src/styles/global/themes.css
Normal file
70
src/styles/global/themes.css
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
.Light-theme {
|
||||
--foreground-color-a: var(--dark-grey-ca);
|
||||
--foreground-color-b: var(--dark-grey-c);
|
||||
--foreground-color-c: var(--dark-grey-b);
|
||||
|
||||
--background-color-a: var(--grey-aa);
|
||||
--background-color-b: var(--grey-a);
|
||||
--background-color-ba: var(--white-b);
|
||||
--background-color-c: var(--white-a);
|
||||
--background-color-d: var(--white-b);
|
||||
|
||||
--taskbar-color: rgba(255, 255, 255, 25%);
|
||||
--background-color-c-hsl: 210, 45%, 90%;
|
||||
}
|
||||
|
||||
.Cherry-theme, .Mango-theme, .Muted-theme, .Aqua-theme, .Grape-theme {
|
||||
--hue: 0;
|
||||
--saturation: 1;
|
||||
--lightness: 1;
|
||||
|
||||
--white-a: hsl(var(--hue), calc(54% * var(--saturation)), calc(95% * var(--lightness)));
|
||||
--white-b: hsl(var(--hue), calc(45% * var(--saturation)), calc(90% * var(--lightness)));
|
||||
--grey-a: hsl(var(--hue), calc(36% * var(--saturation)), calc(85% * var(--lightness)));
|
||||
--grey-aa: hsl(var(--hue), calc(27% * var(--saturation)), calc(72.5% * var(--lightness)));
|
||||
--grey-b: hsl(var(--hue), calc(18% * var(--saturation)), calc(60% * var(--lightness)));
|
||||
--dark-grey-a: hsl(var(--hue), calc(14% * var(--saturation)), calc(40% * var(--lightness)));
|
||||
--dark-grey-b: hsl(var(--hue), calc(29% * var(--saturation)), calc(19% * var(--lightness)));
|
||||
--dark-grey-c: hsl(var(--hue), calc(29% * var(--saturation)), calc(15% * var(--lightness)));
|
||||
--dark-grey-ca: hsl(var(--hue), calc(27% * var(--saturation)), calc(12% * var(--lightness)));
|
||||
--dark-grey-d: hsl(var(--hue), calc(14% * var(--saturation)), calc(10% * var(--lightness)));
|
||||
--dark-grey-e: hsl(var(--hue), calc(12% * var(--saturation)), calc(8% * var(--lightness)));
|
||||
|
||||
--foreground-color-a: var(--white-a);
|
||||
--foreground-color-b: var(--grey-a);
|
||||
--foreground-color-c: var(--grey-b);
|
||||
|
||||
--background-color-a: var(--dark-grey-b);
|
||||
--background-color-b: var(--dark-grey-c);
|
||||
--background-color-ba: var(--dark-grey-ca);
|
||||
--background-color-c: var(--dark-grey-d);
|
||||
--background-color-d: var(--dark-grey-e);
|
||||
}
|
||||
|
||||
.Cherry-theme {
|
||||
--hue: 0;
|
||||
--saturation: 5;
|
||||
--lightness: 1.5;
|
||||
}
|
||||
|
||||
.Mango-theme {
|
||||
--hue: 40;
|
||||
--saturation: 5;
|
||||
--lightness: 2.5;
|
||||
}
|
||||
|
||||
.Muted-theme {
|
||||
--saturation: 0;
|
||||
}
|
||||
|
||||
.Aqua-theme {
|
||||
--hue: 180;
|
||||
--saturation: 4;
|
||||
--lightness: 2;
|
||||
}
|
||||
|
||||
.Grape-theme {
|
||||
--hue: 310;
|
||||
--saturation: 5;
|
||||
--lightness: 1.5;
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
:root {
|
||||
--white-a: hsl(210, 54%, 95%);
|
||||
--white-b: hsl(210, 45%, 90%);
|
||||
--pink-a: #ff9ff3;
|
||||
--pink-b: #f368e0;
|
||||
--yellow-a: #feca57;
|
||||
|
|
@ -17,10 +18,11 @@
|
|||
--purple-a: #5f27cd;
|
||||
--purple-b: #341f97;
|
||||
--grey-a: hsl(210, 36%, 85%);
|
||||
--grey-aa: hsl(210, 27%, 72.5%);
|
||||
--grey-b: hsl(210, 18%, 60%);
|
||||
--dark-grey-a: hsl(211, 14%, 40%);
|
||||
--dark-grey-b: hsl(var(--background-color-a-hsl));
|
||||
--dark-grey-c: hsl(var(--background-color-c-hsl));
|
||||
--dark-grey-a: hsl(212, 14%, 40%);
|
||||
--dark-grey-b: hsl(212, 29%, 19%);
|
||||
--dark-grey-c: hsl(212, 29%, 15%);
|
||||
--dark-grey-ca: hsl(212, 27%, 12%);
|
||||
--dark-grey-d: hsl(212, 14%, 10%);
|
||||
--dark-grey-e: hsl(212, 12%, 8%);
|
||||
|
|
@ -29,13 +31,13 @@
|
|||
--foreground-color-b: var(--grey-a);
|
||||
--foreground-color-c: var(--grey-b);
|
||||
|
||||
--background-color-a: var(--dark-grey-b);
|
||||
--background-color-b: var(--dark-grey-c);
|
||||
--background-color-a: hsl(var(--background-color-a-hsl));
|
||||
--background-color-b: hsl(var(--background-color-c-hsl));
|
||||
--background-color-ba: var(--dark-grey-ca);
|
||||
--background-color-c: var(--dark-grey-d);
|
||||
--background-color-d: var(--dark-grey-e);
|
||||
|
||||
--background-color-a-hsl: 212, 29%, 19%;
|
||||
--background-color-a-hsl: 212, 29%, 19%;
|
||||
--background-color-c-hsl: 212, 29%, 15%;
|
||||
|
||||
--scrollbar-color: hsla(211, 29%, 40%, 25%);
|
||||
|
|
|
|||
Loading…
Reference in a new issue