feat(vpn-desktop-ui): add theme switch into settings (#4217)

This commit is contained in:
Pierre Dommerc
2023-12-04 16:08:44 +01:00
committed by GitHub
parent caf055efc1
commit 145b702f41
7 changed files with 94 additions and 13 deletions
+24 -1
View File
@@ -3,7 +3,7 @@ use tracing::{debug, instrument};
use crate::{
error::{CmdError, CmdErrorSource},
fs::data::AppData,
fs::data::{AppData, UiTheme},
states::SharedAppData,
};
@@ -44,3 +44,26 @@ pub async fn get_app_data(
Ok(data)
}
#[instrument(skip_all)]
#[tauri::command]
pub async fn set_ui_theme(
data_state: State<'_, SharedAppData>,
theme: UiTheme,
) -> Result<(), CmdError> {
debug!("set_ui_theme");
// save the selected UI theme 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.ui_theme = Some(theme);
app_data_store.data = app_data;
app_data_store
.write()
.await
.map_err(|e| CmdError::new(CmdErrorSource::InternalError, e.to_string()))?;
Ok(())
}
+1
View File
@@ -58,6 +58,7 @@ fn main() -> Result<()> {
connection::get_connection_start_time,
app_data::get_app_data,
app_data::set_app_data,
app_data::set_ui_theme,
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
-9
View File
@@ -1,9 +0,0 @@
import { useTranslation } from 'react-i18next';
function Settings() {
const { t } = useTranslation();
return <div>{t('settings')}</div>;
}
export default Settings;
+1 -1
View File
@@ -1,5 +1,5 @@
export * from './home';
export * from './settings';
export { default as NavLayout } from './NavLayout';
export { default as Settings } from './Settings';
export { default as NodeLocation } from './NodeLocation';
export { default as Error } from './Error';
@@ -0,0 +1,58 @@
import { useEffect, useState } from 'react';
import clsx from 'clsx';
import { invoke } from '@tauri-apps/api';
import { Switch } from '@headlessui/react';
import { useMainDispatch, useMainState } from '../../contexts';
import { StateDispatch } from '../../types';
function Settings() {
const state = useMainState();
const dispatch = useMainDispatch() as StateDispatch;
const [enabled, setEnabled] = useState(state.uiTheme === 'Dark');
useEffect(() => {
setEnabled(state.uiTheme === 'Dark');
}, [state.uiTheme]);
const handleThemeChange = async (darkMode: boolean) => {
if (darkMode && state.uiTheme === 'Light') {
dispatch({ type: 'set-ui-theme', theme: 'Dark' });
} else if (!darkMode && state.uiTheme === 'Dark') {
dispatch({ type: 'set-ui-theme', theme: 'Light' });
}
invoke<void>('set_ui_theme', { theme: darkMode ? 'Dark' : 'Light' }).catch(
(e) => {
console.log(e);
},
);
};
return (
<div className="h-full flex flex-col p-4">
<div className="flex flex-row justify-between items-center">
<p className="text-lg text-baltic-sea dark:text-mercury-pinkish">
Dark Mode
</p>
<Switch
checked={enabled}
onChange={handleThemeChange}
className={clsx([
enabled ? 'bg-melon' : 'bg-mercury-pinkish dark:bg-gun-powder',
'relative inline-flex h-6 w-11 items-center rounded-full',
])}
>
<span className="sr-only">Dark mode</span>
<span
className={clsx([
enabled ? 'translate-x-6' : 'translate-x-1',
'inline-block h-4 w-4 transform rounded-full bg-ciment-feet dark:bg-white transition',
])}
/>
</Switch>
</div>
</div>
);
}
export default Settings;
+1
View File
@@ -0,0 +1 @@
export { default as Settings } from './Settings';
+9 -2
View File
@@ -1,5 +1,5 @@
import dayjs from 'dayjs';
import { AppData, AppState, ConnectionState, VpnMode } from '../types';
import { AppData, AppState, ConnectionState, UiTheme, VpnMode } from '../types';
export type StateAction =
| { type: 'set-partial-state'; partialState: Partial<AppState> }
@@ -14,7 +14,8 @@ export type StateAction =
| { type: 'set-connection-start-time'; startTime?: number | null }
| { type: 'set-disconnected' }
| { type: 'reset' }
| { type: 'set-app-data'; data: AppData };
| { type: 'set-app-data'; data: AppData }
| { type: 'set-ui-theme'; theme: UiTheme };
export const initialState: AppState = {
state: 'Disconnected',
@@ -98,6 +99,12 @@ export function reducer(state: AppState, action: StateAction): AppState {
...state,
progressMessages: [...state.progressMessages, action.message],
};
case 'set-ui-theme':
return {
...state,
uiTheme: action.theme,
localAppData: { ...state.localAppData, uiTheme: action.theme },
};
case 'reset':
return initialState;
}