diff --git a/remote_frontend/package-lock.json b/remote_frontend/package-lock.json
index 5ec1cd8..aa5da94 100644
--- a/remote_frontend/package-lock.json
+++ b/remote_frontend/package-lock.json
@@ -9,6 +9,7 @@
"version": "0.0.0",
"dependencies": {
"@fluentui/react-components": "^9.49.0",
+ "@fluentui/react-icons": "^2.0.238",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
@@ -1415,9 +1416,9 @@
}
},
"node_modules/@fluentui/react-icons": {
- "version": "2.0.237",
- "resolved": "https://registry.npmjs.org/@fluentui/react-icons/-/react-icons-2.0.237.tgz",
- "integrity": "sha512-J+6XDB/Y3G3nfNWvKKI6xhUXDN6/xvhksnV+zfXiGb6tqtK7QiihAzvRRgPnKuS3BH/H1TM7k3KC19V0AJrTDg==",
+ "version": "2.0.238",
+ "resolved": "https://registry.npmjs.org/@fluentui/react-icons/-/react-icons-2.0.238.tgz",
+ "integrity": "sha512-2T87k8lP4k2h98aDY2WlSACa2u0WBll1BQ/0+hsS0ir4uvRLRofLi5rtRUz3i1aOymeKvCoQzW6q1m03Z7JEOw==",
"dependencies": {
"@griffel/react": "^1.0.0",
"tslib": "^2.1.0"
diff --git a/remote_frontend/package.json b/remote_frontend/package.json
index 5031631..9cd9ed7 100644
--- a/remote_frontend/package.json
+++ b/remote_frontend/package.json
@@ -11,6 +11,7 @@
},
"dependencies": {
"@fluentui/react-components": "^9.49.0",
+ "@fluentui/react-icons": "^2.0.238",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
diff --git a/remote_frontend/src/App.tsx b/remote_frontend/src/App.tsx
index 005b232..074c9a3 100644
--- a/remote_frontend/src/App.tsx
+++ b/remote_frontend/src/App.tsx
@@ -1,19 +1,8 @@
-import {
- Menu,
- MenuButton,
- MenuItem,
- MenuList,
- MenuPopover,
- MenuTrigger,
- makeStyles,
- typographyStyles,
-} from "@fluentui/react-components";
+import { makeStyles, typographyStyles } from "@fluentui/react-components";
import { ServerApi } from "./api/ServerApi";
import { AuthRouteWidget } from "./routes/AuthRouteWidget";
import { AsyncWidget } from "./widgets/AsyncWidget";
-import { AuthApi } from "./api/AuthApi";
-import { useAlert } from "./hooks/providers/AlertDialogProvider";
-import { useConfirm } from "./hooks/providers/ConfirmDialogProvider";
+import { MainMenu } from "./widgets/MainMenu";
const useStyles = makeStyles({
title: typographyStyles.title2,
@@ -32,20 +21,8 @@ export function App() {
}
function AppInner(): React.ReactElement {
- const alert = useAlert();
- const confirm = useConfirm();
const styles = useStyles();
- const signOut = async () => {
- try {
- if (!(await confirm("Do you really want to sign out?"))) return;
- await AuthApi.SignOut();
- } catch (e) {
- console.error(e);
- alert("Failed to perform sign out!");
- }
- };
-
if (!ServerApi.Config.authenticated && !ServerApi.Config.disable_auth)
return ;
@@ -59,17 +36,7 @@ function AppInner(): React.ReactElement {
>
VirtWebRemote
-
+
);
diff --git a/remote_frontend/src/hooks/providers/ThemeProvider.tsx b/remote_frontend/src/hooks/providers/ThemeProvider.tsx
new file mode 100644
index 0000000..fd419f6
--- /dev/null
+++ b/remote_frontend/src/hooks/providers/ThemeProvider.tsx
@@ -0,0 +1,55 @@
+import {
+ FluentProvider,
+ teamsDarkTheme,
+ teamsHighContrastTheme,
+ teamsLightTheme,
+ webDarkTheme,
+ webLightTheme,
+} from "@fluentui/react-components";
+import React from "react";
+
+export type Theme =
+ | "highcontrast"
+ | "teamsdark"
+ | "teamslight"
+ | "webdark"
+ | "weblight";
+
+type ThemeContext = { theme: Theme; set: (theme: Theme) => void };
+
+const ThemeContextK = React.createContext(null);
+
+export function ThemeProvider(p: React.PropsWithChildren): React.ReactElement {
+ const [theme, setTheme] = React.useState("highcontrast");
+
+ let fluentTheme = teamsHighContrastTheme;
+ switch (theme) {
+ case "teamsdark":
+ fluentTheme = teamsDarkTheme;
+ break;
+ case "teamslight":
+ fluentTheme = teamsLightTheme;
+ break;
+ case "highcontrast":
+ fluentTheme = teamsHighContrastTheme;
+ break;
+ case "webdark":
+ fluentTheme = webDarkTheme;
+ break;
+ case "weblight":
+ fluentTheme = webLightTheme;
+ break;
+ }
+
+ return (
+
+
+ {p.children}
+
+
+ );
+}
+
+export function useTheme(): ThemeContext {
+ return React.useContext(ThemeContextK)!;
+}
diff --git a/remote_frontend/src/main.tsx b/remote_frontend/src/main.tsx
index 2624abb..2ccddd9 100644
--- a/remote_frontend/src/main.tsx
+++ b/remote_frontend/src/main.tsx
@@ -1,25 +1,19 @@
import React from "react";
import ReactDOM from "react-dom/client";
-import "./index.css";
import { App } from "./App";
-import {
- FluentProvider,
- teamsHighContrastTheme,
-} from "@fluentui/react-components";
import { AlertDialogProvider } from "./hooks/providers/AlertDialogProvider";
import { ConfirmDialogProvider } from "./hooks/providers/ConfirmDialogProvider";
+import { ThemeProvider } from "./hooks/providers/ThemeProvider";
+import "./index.css";
ReactDOM.createRoot(document.getElementById("root")!).render(
-
+
-
+
);
diff --git a/remote_frontend/src/widgets/MainMenu.tsx b/remote_frontend/src/widgets/MainMenu.tsx
new file mode 100644
index 0000000..7f4c560
--- /dev/null
+++ b/remote_frontend/src/widgets/MainMenu.tsx
@@ -0,0 +1,69 @@
+import {
+ Menu,
+ MenuButton,
+ MenuItem,
+ MenuList,
+ MenuPopover,
+ MenuTrigger,
+} from "@fluentui/react-components";
+import { Checkmark12Regular } from "@fluentui/react-icons";
+import { AuthApi } from "./../api/AuthApi";
+import { useAlert } from "./../hooks/providers/AlertDialogProvider";
+import { useConfirm } from "./../hooks/providers/ConfirmDialogProvider";
+import { Theme, useTheme } from "./../hooks/providers/ThemeProvider";
+
+export function MainMenu(): React.ReactElement {
+ const alert = useAlert();
+ const confirm = useConfirm();
+
+ const signOut = async () => {
+ try {
+ if (!(await confirm("Do you really want to sign out?"))) return;
+ await AuthApi.SignOut();
+ } catch (e) {
+ console.error(e);
+ alert("Failed to perform sign out!");
+ }
+ };
+ return (
+
+ );
+}
+
+function ThemeMenuItem(p: { label: string; value: Theme }): React.ReactElement {
+ const theme = useTheme();
+
+ return (
+ : undefined}
+ onClick={() => theme.set(p.value)}
+ >
+ {p.label}
+
+ );
+}