diff --git a/nym-vpn/ui/.eslintrc.cjs b/nym-vpn/ui/.eslintrc.cjs index 3eabd85c88..ff65dd7c03 100644 --- a/nym-vpn/ui/.eslintrc.cjs +++ b/nym-vpn/ui/.eslintrc.cjs @@ -45,5 +45,6 @@ module.exports = { groups: ['builtin', 'external', 'parent', 'sibling', 'index'], }, ], + 'import/extensions': ['error', 'never', { json: 'always', svg: 'always' }], }, }; diff --git a/nym-vpn/ui/index.html b/nym-vpn/ui/index.html index 18a2ad3ed0..a548f6417f 100644 --- a/nym-vpn/ui/index.html +++ b/nym-vpn/ui/index.html @@ -1,5 +1,5 @@ - + @@ -8,7 +8,7 @@ -
+
diff --git a/nym-vpn/ui/package.json b/nym-vpn/ui/package.json index 585f048d8e..cd6bbc3034 100644 --- a/nym-vpn/ui/package.json +++ b/nym-vpn/ui/package.json @@ -18,6 +18,8 @@ "tauri": "tauri" }, "dependencies": { + "@headlessui/react": "^1.7.17", + "@headlessui/tailwindcss": "^0.2.0", "@mui/base": "^5.0.0-beta.24", "@tauri-apps/api": "^1.5.0", "clsx": "^2.0.0", diff --git a/nym-vpn/ui/src-tauri/src/commands/connection.rs b/nym-vpn/ui/src-tauri/src/commands/connection.rs index 1da6282600..944337eb53 100644 --- a/nym-vpn/ui/src-tauri/src/commands/connection.rs +++ b/nym-vpn/ui/src-tauri/src/commands/connection.rs @@ -3,11 +3,14 @@ use std::time::Duration; use tauri::{Manager, State}; use time::OffsetDateTime; use tokio::time::sleep; -use tracing::{debug, instrument, trace}; +use tracing::{debug, error, instrument, trace}; use crate::{ error::{CmdError, CmdErrorSource}, - states::{app::ConnectionState, SharedAppState}, + states::{ + app::{ConnectionState, VpnMode}, + SharedAppData, SharedAppState, + }, }; const EVENT_CONNECTION_STATE: &str = "connection-state"; @@ -178,3 +181,37 @@ pub async fn get_connection_start_time( let app_state = state.lock().await; Ok(app_state.connection_start_time.map(|t| t.unix_timestamp())) } + +#[instrument(skip_all)] +#[tauri::command] +pub async fn set_vpn_mode( + app_state: State<'_, SharedAppState>, + data_state: State<'_, SharedAppData>, + mode: VpnMode, +) -> Result<(), CmdError> { + debug!("set_vpn_mode"); + + let mut state = app_state.lock().await; + + if let ConnectionState::Disconnected = state.state { + } else { + let err_message = format!("cannot change vpn mode from state {:?}", state.state); + error!(err_message); + return Err(CmdError::new(CmdErrorSource::CallerError, err_message)); + } + state.vpn_mode = mode.clone(); + + // save the selected mode to disk + let mut app_data_store = data_state.lock().await; + let mut app_data = app_data_store + .read() + .await + .map_err(|e| CmdError::new(CmdErrorSource::InternalError, e.to_string()))?; + app_data.vpn_mode = Some(mode); + app_data_store.data = app_data; + app_data_store + .write() + .await + .map_err(|e| CmdError::new(CmdErrorSource::InternalError, e.to_string()))?; + Ok(()) +} diff --git a/nym-vpn/ui/src-tauri/src/error.rs b/nym-vpn/ui/src-tauri/src/error.rs index 14cac138dc..e4be67cc80 100644 --- a/nym-vpn/ui/src-tauri/src/error.rs +++ b/nym-vpn/ui/src-tauri/src/error.rs @@ -25,7 +25,10 @@ pub struct CmdError { impl CmdError { pub fn new(error: CmdErrorSource, message: String) -> Self { - Self { message, source: error } + Self { + message, + source: error, + } } } diff --git a/nym-vpn/ui/src-tauri/src/fs/data.rs b/nym-vpn/ui/src-tauri/src/fs/data.rs index 1cbc5b6354..18df75cb14 100644 --- a/nym-vpn/ui/src-tauri/src/fs/data.rs +++ b/nym-vpn/ui/src-tauri/src/fs/data.rs @@ -1,11 +1,11 @@ use serde::{Deserialize, Serialize}; use ts_rs::TS; -use crate::states::app::{NodeConfig, PrivacyMode}; +use crate::states::app::{NodeConfig, VpnMode}; #[derive(Default, Serialize, Deserialize, Debug, Clone, TS)] #[ts(export)] -pub enum UiMode { +pub enum UiTheme { Dark, #[default] Light, @@ -17,8 +17,8 @@ pub struct AppData { pub monitoring: Option, pub autoconnect: Option, pub killswitch: Option, - pub ui_mode: Option, - pub privacy_mode: Option, + pub ui_theme: Option, + pub vpn_mode: Option, pub entry_node: Option, pub exit_node: Option, } diff --git a/nym-vpn/ui/src-tauri/src/main.rs b/nym-vpn/ui/src-tauri/src/main.rs index ea94f327b1..be58a9b885 100644 --- a/nym-vpn/ui/src-tauri/src/main.rs +++ b/nym-vpn/ui/src-tauri/src/main.rs @@ -51,6 +51,7 @@ fn main() -> Result<()> { Ok(()) }) .invoke_handler(tauri::generate_handler![ + connection::set_vpn_mode, connection::get_connection_state, connection::connect, connection::disconnect, diff --git a/nym-vpn/ui/src-tauri/src/states/app.rs b/nym-vpn/ui/src-tauri/src/states/app.rs index 07d15d5b1c..8ef242a24b 100644 --- a/nym-vpn/ui/src-tauri/src/states/app.rs +++ b/nym-vpn/ui/src-tauri/src/states/app.rs @@ -22,11 +22,10 @@ pub enum ConnectionState { #[derive(Default, Debug, Serialize, Deserialize, TS, Clone)] #[ts(export)] -pub enum PrivacyMode { - High, - Medium, +pub enum VpnMode { + Mixnet, #[default] - Low, + TwoHop, } #[derive(Debug, Serialize, Deserialize, TS)] @@ -40,7 +39,7 @@ pub struct TunnelConfig { pub struct AppState { pub state: ConnectionState, pub error: Option, - pub privacy_mode: PrivacyMode, + pub vpn_mode: VpnMode, pub entry_node: Option, pub exit_node: Option, pub tunnel: Option, diff --git a/nym-vpn/ui/src-tauri/tauri.conf.json b/nym-vpn/ui/src-tauri/tauri.conf.json index 62e096864f..7c565fd47d 100644 --- a/nym-vpn/ui/src-tauri/tauri.conf.json +++ b/nym-vpn/ui/src-tauri/tauri.conf.json @@ -44,10 +44,10 @@ "windows": [ { "fullscreen": false, - "resizable": false, + "resizable": true, "title": "NymVPN", - "width": 390, - "height": 820 + "width": 440, + "height": 920 } ] } diff --git a/nym-vpn/ui/src/dev/setup.ts b/nym-vpn/ui/src/dev/setup.ts index 9ee60ce6af..b0e8edd092 100644 --- a/nym-vpn/ui/src/dev/setup.ts +++ b/nym-vpn/ui/src/dev/setup.ts @@ -38,8 +38,8 @@ export function mockTauriIPC() { monitoring: false, autoconnect: false, killswitch: false, - ui_mode: 'Dark', - privacy_mode: 'High', + ui_theme: 'Dark', + vpn_mode: 'TwoHop', entry_node: null, exit_node: null, }), diff --git a/nym-vpn/ui/src/i18n/en/home.json b/nym-vpn/ui/src/i18n/en/home.json index 8b89fa7ddc..56929bc48a 100644 --- a/nym-vpn/ui/src/i18n/en/home.json +++ b/nym-vpn/ui/src/i18n/en/home.json @@ -10,13 +10,13 @@ }, "connecting-message": "Establishing connection", "connection-time": "Connection time", - "select-network-title": "Select network", + "select-network-label": "Select network", "select-node-title": "Connect to", "mixnet-mode": { "title": "5-hop mixnet", "desc": "Best for payments, emails, messages" }, - "wg-mode": { + "twohop-mode": { "title": "2-hop WireGuard", "desc": "Best for browsing, streaming, sharing" }, diff --git a/nym-vpn/ui/src/pages/Home.tsx b/nym-vpn/ui/src/pages/Home.tsx deleted file mode 100644 index a2a7951dbe..0000000000 --- a/nym-vpn/ui/src/pages/Home.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import { useTranslation } from 'react-i18next'; -import { invoke } from '@tauri-apps/api'; -import clsx from 'clsx'; -import { useMainDispatch, useMainState } from '../contexts'; -import { ConnectionState, StateDispatch } from '../types'; -import { ConnectionTimer } from '../ui'; - -function Home() { - const state = useMainState(); - const dispatch = useMainDispatch() as StateDispatch; - - const { t } = useTranslation('home'); - - const handleClick = async () => { - if (state.state === 'Connected') { - dispatch({ type: 'disconnect' }); - invoke('disconnect').then((result) => { - console.log(result); - }); - } else if (state.state === 'Disconnected') { - dispatch({ type: 'connect' }); - invoke('connect').then((result) => { - console.log(result); - }); - } - }; - - const statusBadgeDynStyles = { - Connected: [ - 'bg-blanc-nacre-icicle', - 'text-vert-menthe', - 'dark:bg-baltic-sea-quartzite', - ], - Disconnected: [ - 'bg-blanc-nacre-platinum', - 'text-coal-mine-light', - 'dark:bg-baltic-sea-oil', - 'dark:text-coal-mine-dark', - ], - Connecting: [ - 'bg-blanc-nacre-platinum', - 'text-baltic-sea', - 'dark:bg-baltic-sea-oil', - 'dark:text-white', - ], - Disconnecting: [ - 'bg-blanc-nacre-platinum', - 'text-baltic-sea', - 'dark:bg-baltic-sea-oil', - 'dark:text-white', - ], - Unknown: [ - 'bg-blanc-nacre-platinum', - 'text-coal-mine-light', - 'dark:bg-baltic-sea-oil', - 'dark:text-coal-mine-dark', - ], - }; - - const getStatusText = (state: ConnectionState) => { - switch (state) { - case 'Connected': - return t('status.connected'); - case 'Disconnected': - return t('status.disconnected'); - case 'Connecting': - return t('status.connecting'); - case 'Disconnecting': - return t('status.disconnecting'); - case 'Unknown': - return t('status.unknown'); - } - }; - - return ( -
-
-
-
- {getStatusText(state.state)} -
-
-
- {state.loading && state.progressMessages.length > 0 && ( -

- {state.progressMessages[state.progressMessages.length - 1]} -

- )} - {state.state === 'Connected' && } - {state.error && ( -

{state.error}

- )} -
-
-
- -
-
- ); -} - -export default Home; diff --git a/nym-vpn/ui/src/pages/NavLayout.tsx b/nym-vpn/ui/src/pages/NavLayout.tsx index b63148a7e5..2fba78c338 100644 --- a/nym-vpn/ui/src/pages/NavLayout.tsx +++ b/nym-vpn/ui/src/pages/NavLayout.tsx @@ -3,7 +3,7 @@ import { TopBar } from '../ui'; function NavLayout() { return ( -
+
diff --git a/nym-vpn/ui/src/pages/home/ConnectionStatus.tsx b/nym-vpn/ui/src/pages/home/ConnectionStatus.tsx new file mode 100644 index 0000000000..0da9232f4a --- /dev/null +++ b/nym-vpn/ui/src/pages/home/ConnectionStatus.tsx @@ -0,0 +1,84 @@ +import clsx from 'clsx'; +import { useTranslation } from 'react-i18next'; +import { ConnectionState } from '../../types'; +import { useMainState } from '../../contexts'; +import ConnectionTimer from './ConnectionTimer'; + +function ConnectionStatus() { + const state = useMainState(); + + const { t } = useTranslation('home'); + const statusBadgeDynStyles = { + Connected: [ + 'bg-blanc-nacre-icicle', + 'text-vert-menthe', + 'dark:bg-baltic-sea-quartzite', + ], + Disconnected: [ + 'bg-blanc-nacre-platinum', + 'text-coal-mine-light', + 'dark:bg-baltic-sea-oil', + 'dark:text-coal-mine-dark', + ], + Connecting: [ + 'bg-blanc-nacre-platinum', + 'text-baltic-sea', + 'dark:bg-baltic-sea-oil', + 'dark:text-white', + ], + Disconnecting: [ + 'bg-blanc-nacre-platinum', + 'text-baltic-sea', + 'dark:bg-baltic-sea-oil', + 'dark:text-white', + ], + Unknown: [ + 'bg-blanc-nacre-platinum', + 'text-coal-mine-light', + 'dark:bg-baltic-sea-oil', + 'dark:text-coal-mine-dark', + ], + }; + + const getStatusText = (state: ConnectionState) => { + switch (state) { + case 'Connected': + return t('status.connected'); + case 'Disconnected': + return t('status.disconnected'); + case 'Connecting': + return t('status.connecting'); + case 'Disconnecting': + return t('status.disconnecting'); + case 'Unknown': + return t('status.unknown'); + } + }; + return ( +
+
+
+ {getStatusText(state.state)} +
+
+
+ {state.loading && state.progressMessages.length > 0 && ( +

+ {state.progressMessages[state.progressMessages.length - 1]} +

+ )} + {state.state === 'Connected' && } + {state.error && ( +

{state.error}

+ )} +
+
+ ); +} + +export default ConnectionStatus; diff --git a/nym-vpn/ui/src/ui/ConnectionTimer.tsx b/nym-vpn/ui/src/pages/home/ConnectionTimer.tsx similarity index 95% rename from nym-vpn/ui/src/ui/ConnectionTimer.tsx rename to nym-vpn/ui/src/pages/home/ConnectionTimer.tsx index 68b139e188..bc06d93102 100644 --- a/nym-vpn/ui/src/ui/ConnectionTimer.tsx +++ b/nym-vpn/ui/src/pages/home/ConnectionTimer.tsx @@ -1,7 +1,7 @@ import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import dayjs from 'dayjs'; -import { useMainState } from '../contexts'; +import { useMainState } from '../../contexts'; function ConnectionTimer() { const { sessionStartDate } = useMainState(); diff --git a/nym-vpn/ui/src/pages/home/Home.tsx b/nym-vpn/ui/src/pages/home/Home.tsx new file mode 100644 index 0000000000..cc53da9df3 --- /dev/null +++ b/nym-vpn/ui/src/pages/home/Home.tsx @@ -0,0 +1,79 @@ +import { useTranslation } from 'react-i18next'; +import { invoke } from '@tauri-apps/api'; +import clsx from 'clsx'; +import { Button } from '@mui/base'; +import { useMainDispatch, useMainState } from '../../contexts'; +import { ConnectionState, StateDispatch } from '../../types'; +import NetworkModeSelect from './NetworkModeSelect'; +import ConnectionStatus from './ConnectionStatus'; + +function Home() { + const state = useMainState(); + const dispatch = useMainDispatch() as StateDispatch; + + const { t } = useTranslation('home'); + + const handleClick = async () => { + if (state.state === 'Connected') { + dispatch({ type: 'disconnect' }); + invoke('disconnect').then((result) => { + console.log(result); + }); + } else if (state.state === 'Disconnected') { + dispatch({ type: 'connect' }); + invoke('connect').then((result) => { + console.log(result); + }); + } + }; + + const getButtonText = (state: ConnectionState) => { + switch (state) { + case 'Connected': + return t('disconnect'); + case 'Disconnected': + return t('connect'); + case 'Connecting': + return ( +
+ autorenew +
+ ); + case 'Disconnecting': + return ( +
+ autorenew +
+ ); + case 'Unknown': + return t('status.unknown'); + } + }; + + return ( +
+ +
+
+ +
+
+ +
+
+ ); +} + +export default Home; diff --git a/nym-vpn/ui/src/pages/home/NetworkModeSelect.tsx b/nym-vpn/ui/src/pages/home/NetworkModeSelect.tsx new file mode 100644 index 0000000000..432233ff60 --- /dev/null +++ b/nym-vpn/ui/src/pages/home/NetworkModeSelect.tsx @@ -0,0 +1,116 @@ +import { useState } from 'react'; +import { RadioGroup } from '@headlessui/react'; +import { invoke } from '@tauri-apps/api'; +import clsx from 'clsx'; +import { useTranslation } from 'react-i18next'; +import { useMainDispatch, useMainState } from '../../contexts'; +import { StateDispatch, VpnMode } from '../../types'; + +type VpnModeOption = { name: VpnMode; title: string; desc: string }; + +function NetworkModeSelect() { + const state = useMainState(); + const dispatch = useMainDispatch() as StateDispatch; + const [selected, setSelected] = useState(state.vpnMode); + const [loading, setLoading] = useState(false); + + const { t } = useTranslation('home'); + + const handleNetworkModeChange = async (value: VpnMode) => { + if (state.state === 'Disconnected' && value !== state.vpnMode) { + setLoading(true); + try { + await invoke('set_vpn_mode', { mode: value }); + dispatch({ type: 'set-vpn-mode', mode: value }); + } catch (e) { + console.log(e); + } finally { + setLoading(false); + } + } + }; + + const vpnModes: VpnModeOption[] = [ + { + name: 'Mixnet', + title: t('mixnet-mode.title'), + desc: t('mixnet-mode.desc'), + }, + { + name: 'TwoHop', + title: t('twohop-mode.title'), + desc: t('twohop-mode.desc'), + }, + ]; + + const handleSelect = (value: VpnMode) => { + setSelected(value); + handleNetworkModeChange(value); + }; + + return ( +
+ + + {t('select-network-label')} + +
+ {vpnModes.map((mode) => ( + + clsx([ + 'bg-white dark:bg-baltic-sea-jaguar relative flex rounded-lg px-5 py-3 shadow-md focus:outline-none', + (state.state !== 'Disconnected' || loading) && + 'cursor-not-allowed', + checked && + 'ring-0 ring-melon ring-offset-2 ring-offset-melon', + state.state === 'Disconnected' && 'cursor-pointer', + ]) + } + disabled={state.state !== 'Disconnected' || loading} + > + {({ checked }) => { + return ( +
+ {checked ? ( + + radio_button_checked + + ) : ( + + radio_button_unchecked + + )} +
+
+ + {mode.title} + + + {mode.desc} + +
+
+
+ ); + }} +
+ ))} +
+
+
+ ); +} + +export default NetworkModeSelect; diff --git a/nym-vpn/ui/src/pages/home/index.ts b/nym-vpn/ui/src/pages/home/index.ts new file mode 100644 index 0000000000..c2d92a5746 --- /dev/null +++ b/nym-vpn/ui/src/pages/home/index.ts @@ -0,0 +1 @@ +export { default as Home } from './Home'; diff --git a/nym-vpn/ui/src/pages/index.ts b/nym-vpn/ui/src/pages/index.ts index 69154de097..c0d83e6544 100644 --- a/nym-vpn/ui/src/pages/index.ts +++ b/nym-vpn/ui/src/pages/index.ts @@ -1,5 +1,5 @@ +export * from './home'; export { default as NavLayout } from './NavLayout'; -export { default as Home } from './Home'; export { default as Settings } from './Settings'; export { default as NodeLocation } from './NodeLocation'; export { default as Error } from './Error'; diff --git a/nym-vpn/ui/src/state/main.ts b/nym-vpn/ui/src/state/main.ts index e339ec781c..d54627a219 100644 --- a/nym-vpn/ui/src/state/main.ts +++ b/nym-vpn/ui/src/state/main.ts @@ -1,9 +1,10 @@ import dayjs from 'dayjs'; -import { AppData, AppState, ConnectionState } from '../types'; +import { AppData, AppState, ConnectionState, VpnMode } from '../types'; export type StateAction = | { type: 'set-partial-state'; partialState: Partial } | { type: 'change-connection-state'; state: ConnectionState } + | { type: 'set-vpn-mode'; mode: VpnMode } | { type: 'set-error'; error: string } | { type: 'reset-error' } | { type: 'new-progress-message'; message: string } @@ -18,16 +19,16 @@ export type StateAction = export const initialState: AppState = { state: 'Disconnected', loading: false, - privacyMode: 'High', + vpnMode: 'TwoHop', tunnel: { name: 'nym', id: 'nym' }, - uiMode: 'Light', + uiTheme: 'Light', progressMessages: [], localAppData: { monitoring: false, autoconnect: false, killswitch: false, - uiMode: 'Light', - privacyMode: 'High', + uiTheme: 'Light', + vpnMode: 'TwoHop', entryNode: null, exitNode: null, }, @@ -35,6 +36,12 @@ export const initialState: AppState = { export function reducer(state: AppState, action: StateAction): AppState { switch (action.type) { + case 'set-vpn-mode': + return { + ...state, + vpnMode: action.mode, + localAppData: { ...state.localAppData, vpnMode: action.mode }, + }; case 'set-partial-state': { return { ...state, ...action.partialState }; } diff --git a/nym-vpn/ui/src/state/provider.tsx b/nym-vpn/ui/src/state/provider.tsx index 60eeedc028..981a23973a 100644 --- a/nym-vpn/ui/src/state/provider.tsx +++ b/nym-vpn/ui/src/state/provider.tsx @@ -48,8 +48,8 @@ export function MainStateProvider({ children }: Props) { autoconnect: data.autoconnect || false, monitoring: data.monitoring || false, killswitch: data.killswitch || false, - uiMode: data.ui_mode || 'Light', - privacyMode: data.privacy_mode || 'High', + uiTheme: data.ui_theme || 'Light', + vpnMode: data.vpn_mode || 'TwoHop', entryNode: data.entry_node, exitNode: data.exit_node, }, @@ -57,8 +57,8 @@ export function MainStateProvider({ children }: Props) { dispatch({ type: 'set-partial-state', partialState: { - uiMode: data.ui_mode || 'Light', - privacyMode: data.privacy_mode || 'High', + uiTheme: data.ui_theme || 'Light', + vpnMode: data.vpn_mode || 'TwoHop', }, }); }) diff --git a/nym-vpn/ui/src/types/app-data.ts b/nym-vpn/ui/src/types/app-data.ts index 940fb182b0..73d6f0c189 100644 --- a/nym-vpn/ui/src/types/app-data.ts +++ b/nym-vpn/ui/src/types/app-data.ts @@ -1,6 +1,6 @@ -import { PrivacyMode } from './app-state'; +import { VpnMode } from './app-state'; -export type UiMode = 'Dark' | 'Light'; +export type UiTheme = 'Dark' | 'Light'; export interface NodeConfig { id: string; @@ -11,8 +11,8 @@ export interface AppData { monitoring: boolean; autoconnect: boolean; killswitch: boolean; - uiMode: UiMode; - privacyMode: PrivacyMode; + uiTheme: UiTheme; + vpnMode: VpnMode; entryNode?: NodeConfig | null; exitNode?: NodeConfig | null; } @@ -22,8 +22,8 @@ export interface AppDataFromBackend { monitoring: boolean | null; autoconnect: boolean | null; killswitch: boolean | null; - ui_mode: UiMode | null; - privacy_mode: PrivacyMode; + ui_theme: UiTheme | null; + vpn_mode: VpnMode; entry_node: NodeConfig | null; exit_node: NodeConfig | null; } diff --git a/nym-vpn/ui/src/types/app-state.ts b/nym-vpn/ui/src/types/app-state.ts index 0b190ff37d..c30f0aa5e9 100644 --- a/nym-vpn/ui/src/types/app-state.ts +++ b/nym-vpn/ui/src/types/app-state.ts @@ -10,7 +10,7 @@ export type ConnectionState = | 'Disconnecting' | 'Unknown'; -export type PrivacyMode = 'High' | 'Medium' | 'Low'; +export type VpnMode = 'TwoHop' | 'Mixnet'; export interface TunnelConfig { id: string; @@ -23,9 +23,9 @@ export type AppState = { error?: string | null; progressMessages: string[]; sessionStartDate?: Dayjs | null; - privacyMode: PrivacyMode; + vpnMode: VpnMode; tunnel: TunnelConfig; - uiMode: 'Light' | 'Dark'; + uiTheme: 'Light' | 'Dark'; localAppData: AppData; }; diff --git a/nym-vpn/ui/src/types/routes.ts b/nym-vpn/ui/src/types/routes.ts index b30777985c..a18280924e 100644 --- a/nym-vpn/ui/src/types/routes.ts +++ b/nym-vpn/ui/src/types/routes.ts @@ -1,3 +1,3 @@ -import { routes } from '../constants.ts'; +import { routes } from '../constants'; export type Routes = (typeof routes)[keyof typeof routes]; diff --git a/nym-vpn/ui/src/ui/ThemeSetter.tsx b/nym-vpn/ui/src/ui/ThemeSetter.tsx index 3e43226846..99941e74cc 100644 --- a/nym-vpn/ui/src/ui/ThemeSetter.tsx +++ b/nym-vpn/ui/src/ui/ThemeSetter.tsx @@ -7,10 +7,10 @@ export default function ThemeSetter({ }: { children: React.ReactNode; }) { - const { uiMode } = useMainState(); + const { uiTheme } = useMainState(); return ( -
+
{children}
); diff --git a/nym-vpn/ui/src/ui/TopBar.tsx b/nym-vpn/ui/src/ui/TopBar.tsx index 3785dc4bc9..db31a5fcb3 100644 --- a/nym-vpn/ui/src/ui/TopBar.tsx +++ b/nym-vpn/ui/src/ui/TopBar.tsx @@ -67,7 +67,7 @@ export default function TopBar() { }, [location.pathname, navBarData]); return ( -