Skip to content

Commit

Permalink
Implemented the ability to change the appearance of the application.
Browse files Browse the repository at this point in the history
Further cleanups are needed.
  • Loading branch information
lupusA committed Dec 11, 2023
1 parent e5c3d3e commit 91204d8
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 27 deletions.
83 changes: 58 additions & 25 deletions src/contexts/UIPreferencesContext.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,38 @@
import React, { ReactNode, useEffect, useState } from 'react';
import React, { ReactNode, useCallback, useEffect, useState } from 'react';
import axios from 'axios';

export const PAGE_SIZES = [10, 20, 30, 40, 50, 100];
export const UIPreferencesContext = React.createContext<UIPreferences>({} as UIPreferences);

const DEFAULT_PREFERENCES = { pageSize: PAGE_SIZES[0], bytesStringBase2: false, defaultSnapshotViewAll: false, theme: getDefaultTheme() } as SerializedUIPreferences;
const DEFAULT_PREFERENCES = { pageSize: PAGE_SIZES[0], bytesStringBase2: false, defaultSnapshotViewAll: false, theme: getDefaultTheme(), preferWebDav: false, fontSize: "fs-6" } as SerializedUIPreferences;
const PREFERENCES_URL = '/api/v1/ui-preferences';

export type Theme = "light" | "dark" | "pastel" | "ocean";
export type PageSize = 10 | 20 | 30 | 40 | 50 | 100;
export type fontSize = "fs-6" | "fs-5" | "fs-4" | "fs-3";

export interface UIPreferences {
get pageSize(): PageSize
get theme(): Theme
get bytesStringBase2(): boolean
get defaultSnapshotViewAll(): boolean
get preferWebDav(): boolean
get fontSize(): fontSize
setTheme: (theme: Theme) => void
setPageSize: (pageSize: number) => void
setByteStringBase: (bytesStringBase2: String) => void
setDefaultSnapshotViewAll: (defaultSnapshotView: boolean) => void
setPreferWebDav: (preferWebDav: String) => void
setFontSize: (size: String) => void
}

interface SerializedUIPreferences {
pageSize?: number
bytesStringBase2?: boolean
defaultSnapshotView?: boolean
theme: Theme | undefined
theme: Theme
preferWebDav?: boolean
fontSize: fontSize
}

export interface UIPreferenceProviderProps {
Expand Down Expand Up @@ -62,6 +69,38 @@ function normalizePageSize(pageSize: number): PageSize {

export function UIPreferenceProvider(props: UIPreferenceProviderProps) {
const [preferences, setPreferences] = useState(DEFAULT_PREFERENCES);
/**
*
* @param theme
* @returns
*/
const setTheme = useCallback((theme: Theme) => setPreferences(oldPreferences => {
syncTheme(theme, oldPreferences.theme);
return { ...oldPreferences, theme };
}),[]);

const setPageSize = (pageSize: PageSize) => setPreferences(oldPreferences => {
return { ...oldPreferences, pageSize };
});

const setByteStringBase = (input: String) => setPreferences(oldPreferences => {
var bytesStringBase2 = input === "true";
return { ...oldPreferences, bytesStringBase2 };
});

const setDefaultSnapshotViewAll = (input: boolean) => setPreferences(oldPreferences => {
return { ...oldPreferences, input };
});

const setPreferWebDav = (input: String) => setPreferences(oldPreferences => {
var preferWebDav = input === "true";
return { ...oldPreferences, preferWebDav };
});

const setFontSize = useCallback((fontSize: fontSize) => setPreferences(oldPreferences => {
syncFontSize(fontSize, oldPreferences.fontSize);
return { ...oldPreferences, fontSize };
}),[]);

useEffect(() => {
axios.get(PREFERENCES_URL).then(result => {
Expand All @@ -74,11 +113,12 @@ export function UIPreferenceProvider(props: UIPreferenceProviderProps) {
} else {
storedPreferences.pageSize = normalizePageSize(storedPreferences.pageSize);
}
syncTheme(storedPreferences.theme)
setTheme(storedPreferences.theme);
setFontSize(storedPreferences.fontSize);
setPreferences(storedPreferences);
}).catch(err => console.error(err));

}, []);
}, [setTheme, setFontSize]);

useEffect(() => {
if (!preferences) {
Expand All @@ -93,36 +133,29 @@ export function UIPreferenceProvider(props: UIPreferenceProviderProps) {
* @param theme
* The theme to be set
*/
const syncTheme = (theme: Theme) => {
const syncTheme = (newTheme: Theme, oldTheme: Theme) => {
var doc = document.querySelector("html")!;
doc.className = theme
if (!doc.classList.replace(oldTheme, newTheme)) {
doc.classList.add(newTheme)
}
}

/**
* Synchronizes the selected theme with the html class
*
* @param theme
* @returns
* The theme to be set
*/
const setTheme = (theme: Theme) => setPreferences(oldPreferences => {
syncTheme(theme);
return { ...oldPreferences, theme };
});

const setPageSize = (pageSize: PageSize) => setPreferences(oldPreferences => {
return { ...oldPreferences, pageSize };
});
const syncFontSize = (newFontSize: fontSize, oldFontSize: fontSize) => {
var doc = document.querySelector("html")!;
if (!doc.classList.replace(oldFontSize, newFontSize)) {
doc.classList.add(newFontSize)
}
}

const setByteStringBase = (input: String) => setPreferences(oldPreferences => {
var bytesStringBase2 = input === "true";
return { ...oldPreferences, bytesStringBase2 };
});

const setDefaultSnapshotViewAll = (input: boolean) => setPreferences(oldPreferences => {
var defaultSnapshotViewAll = input;
return { ...oldPreferences, defaultSnapshotViewAll };
});

const providedValue = { ...preferences, setTheme, setPageSize, setByteStringBase, setDefaultSnapshotViewAll} as UIPreferences;
const providedValue = { ...preferences, setTheme, setPageSize, setByteStringBase, setDefaultSnapshotViewAll, setPreferWebDav, setFontSize } as UIPreferences;

return <UIPreferencesContext.Provider value={providedValue}>
{props.children}
Expand Down
22 changes: 21 additions & 1 deletion src/pages/Preferences.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { UIPreferencesContext } from '../contexts/UIPreferencesContext';
*/
export class Preferences extends Component {
render() {
const { pageSize, theme, bytesStringBase2, setByteStringBase, setTheme } = this.context;
const { pageSize, theme, bytesStringBase2, preferWebDav, fontSize, setByteStringBase, setTheme, setPreferWebDav, setFontSize} = this.context;
return <>
<form>
<div className='form-group'>
Expand All @@ -29,6 +29,26 @@ export class Preferences extends Component {
<small hmtlfor='bytesBaseInput' id='bytesHelp' className='form-text text-muted'>Specifies the representation of bytes</small>
</div>
<br />
<div className='form-group'>
<label className='label-description'>Preferred filesystem for mounts</label>
<select className="form-select form-select-sm" title='Select filesystem type for mounts' id='mountOptionInput' value={preferWebDav} onChange={e => setPreferWebDav(e.target.value)}>
<option value="false">Fuse</option>
<option value="true">WebDav</option>
</select>
<small hmtlfor="mountOptionInput" id='mountOptionHelp' className='form-text text-muted'>Specifies the filesystem that KopiaUI uses to mount snapshots</small>
</div>
<br />
<div className='form-group'>
<label className='label-description'>Appereance</label>
<select className="form-select form-select-sm" title='Select font size' id='fontSizeInput' value={fontSize} onChange={e => setFontSize(e.target.value)}>
<option value="fs-6">small</option>
<option value="fs-5">medium</option>
<option value="fs-4">large</option>
<option value="fs-3">larger</option>
</select>
<small hmtlfor="fontSizeInput" id='fontSizeHelp' className='form-text text-muted'>Specifies the font size</small>
</div>
<br />
<div className='form-group'>
<label className='label-description'>Page size</label>
<input className='form-control form-control-sm' id='pageSizeInput'
Expand Down
4 changes: 3 additions & 1 deletion src/pages/SnapshotDirectory.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Spinner from 'react-bootstrap/Spinner';
import { DirectoryItems } from "../components/DirectoryItems";
import { CLIEquivalent } from '../utils/uiutil';
import { DirectoryBreadcrumbs } from "../components/DirectoryBreadcrumbs";
import { UIPreferencesContext } from '../contexts/UIPreferencesContext';

export class SnapshotDirectory extends Component {
constructor() {
Expand Down Expand Up @@ -68,7 +69,7 @@ export class SnapshotDirectory extends Component {
}

mount() {
axios.post('/api/v1/mounts', { "root": this.state.oid }).then(result => {
axios.post('/api/v1/mounts', { "root": this.state.oid, "options": {"PreferWebDav": this.context.preferWebDav}}).then(result => {
this.setState({
mountInfo: result.data,
});
Expand Down Expand Up @@ -151,3 +152,4 @@ export class SnapshotDirectory extends Component {
</>
}
}
SnapshotDirectory.contextType = UIPreferencesContext

0 comments on commit 91204d8

Please sign in to comment.