diff --git a/nym-vpn/ui/index.html b/nym-vpn/ui/index.html
index eaeca159bd..a548f6417f 100644
--- a/nym-vpn/ui/index.html
+++ b/nym-vpn/ui/index.html
@@ -1,5 +1,5 @@
-
+
diff --git a/nym-vpn/ui/src-tauri/src/commands/app_data.rs b/nym-vpn/ui/src-tauri/src/commands/app_data.rs
index 901726d2f4..539b3f413f 100644
--- a/nym-vpn/ui/src-tauri/src/commands/app_data.rs
+++ b/nym-vpn/ui/src-tauri/src/commands/app_data.rs
@@ -78,6 +78,28 @@ pub async fn set_ui_theme(
Ok(())
}
+#[instrument(skip(data_state))]
+#[tauri::command]
+pub async fn set_root_font_size(
+ data_state: State<'_, SharedAppData>,
+ size: u32,
+) -> Result<(), CmdError> {
+ debug!("set_root_font_size");
+
+ 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.ui_root_font_size = Some(size);
+ app_data_store.data = app_data;
+ app_data_store
+ .write()
+ .await
+ .map_err(|e| CmdError::new(CmdErrorSource::InternalError, e.to_string()))?;
+ Ok(())
+}
+
#[instrument(skip(data_state))]
#[tauri::command]
pub async fn set_entry_location_selector(
diff --git a/nym-vpn/ui/src-tauri/src/fs/data.rs b/nym-vpn/ui/src-tauri/src/fs/data.rs
index e6b3952316..797009af2a 100644
--- a/nym-vpn/ui/src-tauri/src/fs/data.rs
+++ b/nym-vpn/ui/src-tauri/src/fs/data.rs
@@ -19,6 +19,7 @@ pub struct AppData {
pub killswitch: Option,
pub entry_location_selector: Option,
pub ui_theme: Option,
+ pub ui_root_font_size: 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 34798e19b5..6cdc3815ab 100644
--- a/nym-vpn/ui/src-tauri/src/main.rs
+++ b/nym-vpn/ui/src-tauri/src/main.rs
@@ -109,6 +109,7 @@ async fn main() -> Result<()> {
app_data::set_ui_theme,
app_data::set_entry_location_selector,
app_data::get_node_countries,
+ app_data::set_root_font_size,
node_location::set_node_location,
node_location::get_default_node_location,
])
diff --git a/nym-vpn/ui/src/constants.ts b/nym-vpn/ui/src/constants.ts
index 026e015917..ee33ed2fcd 100644
--- a/nym-vpn/ui/src/constants.ts
+++ b/nym-vpn/ui/src/constants.ts
@@ -9,3 +9,5 @@ export const AppName = 'NymVPN';
export const ConnectionEvent = 'connection-state';
export const ProgressEvent = 'connection-progress';
export const QuickConnectPrefix = 'Fastest';
+// TODO ⚠ keep this value in sync with the one declared in `index.html`
+export const DefaultRootFontSize = 12; // in px
diff --git a/nym-vpn/ui/src/dev/setup.ts b/nym-vpn/ui/src/dev/setup.ts
index f07e3b8f18..7bedb656a7 100644
--- a/nym-vpn/ui/src/dev/setup.ts
+++ b/nym-vpn/ui/src/dev/setup.ts
@@ -65,6 +65,10 @@ export function mockTauriIPC() {
);
}
+ if (cmd === 'set_root_font_size') {
+ return new Promise((resolve) => resolve());
+ }
+
if (cmd === 'get_app_data') {
return new Promise((resolve) =>
resolve({
@@ -73,6 +77,7 @@ export function mockTauriIPC() {
killswitch: false,
entry_location_selector: false,
ui_theme: 'Dark',
+ ui_root_font_size: 12,
vpn_mode: 'TwoHop',
entry_node: {
country: {
diff --git a/nym-vpn/ui/src/pages/home/Home.tsx b/nym-vpn/ui/src/pages/home/Home.tsx
index 7987c52066..ef6d8ede54 100644
--- a/nym-vpn/ui/src/pages/home/Home.tsx
+++ b/nym-vpn/ui/src/pages/home/Home.tsx
@@ -90,7 +90,9 @@ function Home() {
{country.name}
-
+
arrow_right
diff --git a/nym-vpn/ui/src/pages/settings/Settings.tsx b/nym-vpn/ui/src/pages/settings/Settings.tsx
index 19fa07937d..7d1044bc8a 100644
--- a/nym-vpn/ui/src/pages/settings/Settings.tsx
+++ b/nym-vpn/ui/src/pages/settings/Settings.tsx
@@ -4,6 +4,7 @@ import { invoke } from '@tauri-apps/api';
import { Switch } from '@headlessui/react';
import { useMainDispatch, useMainState } from '../../contexts';
import { StateDispatch } from '../../types';
+import UiScaler from './UiScaler';
function Settings() {
const state = useMainState();
@@ -55,6 +56,7 @@ function Settings() {
/>
+
);
}
diff --git a/nym-vpn/ui/src/pages/settings/UiScaler.tsx b/nym-vpn/ui/src/pages/settings/UiScaler.tsx
new file mode 100644
index 0000000000..7cde54f24b
--- /dev/null
+++ b/nym-vpn/ui/src/pages/settings/UiScaler.tsx
@@ -0,0 +1,47 @@
+import { ChangeEvent, useEffect, useState } from 'react';
+import { invoke } from '@tauri-apps/api';
+import { useMainDispatch, useMainState } from '../../contexts';
+import { CmdError, StateDispatch } from '../../types';
+
+function UiScaler() {
+ const [slideValue, setSlideValue] = useState(12);
+ const dispatch = useMainDispatch() as StateDispatch;
+ const { rootFontSize } = useMainState();
+
+ useEffect(() => {
+ setSlideValue(rootFontSize);
+ }, [rootFontSize]);
+
+ const handleChange = (e: ChangeEvent) => {
+ setSlideValue(parseInt(e.target.value));
+ dispatch({ type: 'set-root-font-size', size: slideValue });
+ };
+
+ const setNewFontSize = () => {
+ document.documentElement.style.fontSize = `${slideValue}px`;
+ dispatch({ type: 'set-root-font-size', size: slideValue });
+ invoke('set_root_font_size', { size: slideValue }).catch((e: CmdError) => {
+ console.warn(`backend error: ${e.source} - ${e.message}`);
+ });
+ };
+
+ return (
+
+
+ {`Zoom level: ${slideValue}`}
+
+
+
+ );
+}
+
+export default UiScaler;
diff --git a/nym-vpn/ui/src/state/main.ts b/nym-vpn/ui/src/state/main.ts
index 48459804f0..824da4c14b 100644
--- a/nym-vpn/ui/src/state/main.ts
+++ b/nym-vpn/ui/src/state/main.ts
@@ -26,7 +26,8 @@ export type StateAction =
| { type: 'set-ui-theme'; theme: UiTheme }
| { type: 'set-countries'; countries: Country[] }
| { type: 'set-node-location'; payload: { hop: NodeHop; country: Country } }
- | { type: 'set-default-node-location'; country: Country };
+ | { type: 'set-default-node-location'; country: Country }
+ | { type: 'set-root-font-size'; size: number };
export const initialState: AppState = {
state: 'Disconnected',
@@ -43,6 +44,7 @@ export const initialState: AppState = {
code: 'FR',
},
countries: [],
+ rootFontSize: 12,
};
export function reducer(state: AppState, action: StateAction): AppState {
@@ -145,6 +147,11 @@ export function reducer(state: AppState, action: StateAction): AppState {
...state,
defaultNodeLocation: action.country,
};
+ case 'set-root-font-size':
+ return {
+ ...state,
+ rootFontSize: action.size,
+ };
case 'reset':
return initialState;
}
diff --git a/nym-vpn/ui/src/state/provider.tsx b/nym-vpn/ui/src/state/provider.tsx
index 9cb376aaf0..dcbf00946e 100644
--- a/nym-vpn/ui/src/state/provider.tsx
+++ b/nym-vpn/ui/src/state/provider.tsx
@@ -7,6 +7,7 @@ import {
ConnectionState,
Country,
} from '../types';
+import { DefaultRootFontSize } from '../constants';
import { initialState, reducer } from './main';
import { useTauriEvents } from './useTauriEvents';
@@ -89,10 +90,16 @@ export function MainStateProvider({ children }: Props) {
.then((data) => {
console.log('app data read from disk:');
console.log(data);
+
+ if (data.ui_root_font_size) {
+ document.documentElement.style.fontSize = `${data.ui_root_font_size}px`;
+ }
+
const partialState: Partial = {
entrySelector: data.entry_location_selector || false,
uiTheme: data.ui_theme || 'Light',
vpnMode: data.vpn_mode || 'TwoHop',
+ rootFontSize: data.ui_root_font_size || DefaultRootFontSize,
};
if (data.entry_node_location) {
partialState.entryNodeLocation = data.entry_node_location;
diff --git a/nym-vpn/ui/src/types/app-data.ts b/nym-vpn/ui/src/types/app-data.ts
index 931c0ead59..6a0bb2f5be 100644
--- a/nym-vpn/ui/src/types/app-data.ts
+++ b/nym-vpn/ui/src/types/app-data.ts
@@ -19,6 +19,7 @@ export interface AppDataFromBackend {
killswitch: boolean | null;
entry_location_selector: boolean | null;
ui_theme: UiTheme | null;
+ ui_root_font_size: number | null;
vpn_mode: VpnMode | null;
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 bc0dcde5e5..7ace38c3c5 100644
--- a/nym-vpn/ui/src/types/app-state.ts
+++ b/nym-vpn/ui/src/types/app-state.ts
@@ -31,6 +31,7 @@ export type AppState = {
exitNodeLocation: Country | null;
defaultNodeLocation: Country;
countries: Country[];
+ rootFontSize: number;
};
export type ConnectionEventPayload = {