Skip to content

Commit 0f34896

Browse files
committed
Add configurable font
Issue #86
1 parent 5a494c6 commit 0f34896

9 files changed

Lines changed: 155 additions & 38 deletions

File tree

.github/workflows/build.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,7 @@ jobs:
7171
if: matrix.platform.os == 'ubuntu-latest'
7272
run: |
7373
sudo apt-get update
74-
sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf libasound2-dev
75-
74+
sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf libasound2-dev libfontconfig-dev
7675
- name: install npm packages
7776
run: npm ci
7877

src-tauri/Cargo.lock

Lines changed: 77 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src-tauri/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ hyper-tls = "0.5.0"
3131
notify-rust = "4.8.0"
3232
flate2 = "1.0.26"
3333
maxminddb = "0.23"
34+
font-loader = "0.11.0"
3435

3536
[target.'cfg(windows)'.dependencies]
3637
winreg = "0.50.0"

src-tauri/src/commands.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
// along with this program. If not, see <https://www.gnu.org/licenses/>.
1616

1717
use base64::{engine::general_purpose::STANDARD as b64engine, Engine as _};
18+
use font_loader::system_fonts;
1819
use lava_torrent::torrent::v1::Torrent;
1920
use tauri::{Manager, State};
2021

@@ -239,3 +240,8 @@ pub async fn pass_to_window(
239240
);
240241
}
241242
}
243+
244+
#[tauri::command]
245+
pub async fn list_system_fonts() -> Vec<String> {
246+
system_fonts::query_all()
247+
}

src-tauri/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ fn main() {
171171
commands::cancel_create_torrent,
172172
commands::save_create_torrent,
173173
commands::pass_to_window,
174+
commands::list_system_fonts,
174175
])
175176
.manage(ListenerHandle(Arc::new(RwLock::new(ipc))))
176177
.manage(TorrentCacheHandle::default())

src/components/mantinetheme.tsx

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,14 @@ import { ColorSchemeProvider, Global, MantineProvider } from "@mantine/core";
2020
import type { ColorScheme, MantineThemeOverride } from "@mantine/core";
2121
import { useColorScheme } from "@mantine/hooks";
2222
import { ConfigContext } from "config";
23-
import { FontsizeContextProvider, GlobalStyleOverridesContextProvider, useFontSize, useGlobalStyleOverrides } from "themehooks";
24-
import React, { useCallback, useContext, useState } from "react";
23+
import { FontsizeContextProvider, GlobalStyleOverridesContext, useFontSize, useGlobalStyleOverrides } from "themehooks";
24+
import React, { useCallback, useContext, useEffect, useMemo, useState } from "react";
2525

26-
const Theme: (colorScheme: ColorScheme) => MantineThemeOverride = (colorScheme) => ({
26+
const Theme: (colorScheme: ColorScheme, font?: string) => MantineThemeOverride = (colorScheme, font) => ({
2727
colorScheme,
28-
fontFamily: "system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif",
28+
fontFamily: font ?? "system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif",
2929
headings: {
30-
fontFamily: "system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif",
30+
fontFamily: font ?? "system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif",
3131
},
3232
components: {
3333
Table: {
@@ -140,15 +140,26 @@ export default function CustomMantineProvider({ children }: { children: React.Re
140140
setColorScheme(value);
141141
}, [config, colorScheme]);
142142

143+
const [style, setStyle] = useState(config.values.interface.styleOverrides);
144+
145+
useEffect(() => {
146+
config.values.interface.styleOverrides = style;
147+
console.log("Style written to config", style);
148+
}, [config, style]);
149+
150+
const theme = useMemo(() => {
151+
return Theme(colorScheme, style.font);
152+
}, [colorScheme, style.font]);
153+
143154
return (
144155
<ColorSchemeProvider colorScheme={colorScheme} toggleColorScheme={toggleColorScheme}>
145156
<FontsizeContextProvider>
146-
<GlobalStyleOverridesContextProvider>
147-
<MantineProvider withGlobalStyles withNormalizeCSS theme={Theme(colorScheme)}>
157+
<GlobalStyleOverridesContext.Provider value={{ ...style, setStyle }}>
158+
<MantineProvider withGlobalStyles withNormalizeCSS theme={theme}>
148159
<GlobalStyles />
149160
{children}
150161
</MantineProvider>
151-
</GlobalStyleOverridesContextProvider>
162+
</GlobalStyleOverridesContext.Provider>
152163
</FontsizeContextProvider>
153164
</ColorSchemeProvider>
154165
);

src/components/modals/interfacepanel.tsx

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,21 @@
1616
* along with this program. If not, see <https://www.gnu.org/licenses/>.
1717
*/
1818

19-
import React, { useCallback } from "react";
20-
import { Checkbox, Grid, NumberInput, Textarea, useMantineTheme } from "@mantine/core";
19+
import React, { useCallback, useEffect, useState } from "react";
20+
import { Checkbox, Grid, NativeSelect, NumberInput, Textarea, useMantineTheme } from "@mantine/core";
2121
import type { UseFormReturnType } from "@mantine/form";
2222
import type { ColorSetting } from "components/colorswatch";
2323
import ColorChooser from "components/colorswatch";
2424
import { useGlobalStyleOverrides } from "themehooks";
25+
const { TAURI, invoke } = await import(/* webpackChunkName: "taurishim" */"taurishim");
2526

2627
export interface InterfaceFormValues {
2728
interface: {
29+
styleOverrides: {
30+
color?: ColorSetting,
31+
backgroundColor?: ColorSetting,
32+
font?: string,
33+
},
2834
skipAddDialog: boolean,
2935
numLastSaveDirs: number,
3036
defaultTrackers: string[],
@@ -33,15 +39,39 @@ export interface InterfaceFormValues {
3339

3440
export function InterfaceSettigsPanel<V extends InterfaceFormValues>(props: { form: UseFormReturnType<V> }) {
3541
const theme = useMantineTheme();
36-
const { color, backgroundColor, setStyle } = useGlobalStyleOverrides();
42+
const { color, backgroundColor, font, setStyle } = useGlobalStyleOverrides();
43+
const [systemFonts, setSystemFonts] = useState<string[]>(["Default"]);
44+
45+
useEffect(() => {
46+
if (TAURI) {
47+
invoke<string[]>("list_system_fonts").then((fonts) => {
48+
fonts.sort();
49+
setSystemFonts(["Default"].concat(fonts));
50+
}).catch(console.error);
51+
} else {
52+
setSystemFonts(["Default", "Arial", "Verdana", "Tahoma", "Roboto"]);
53+
}
54+
}, []);
55+
56+
const { setFieldValue } = props.form as unknown as UseFormReturnType<InterfaceFormValues>;
3757

3858
const setTextColor = useCallback((color: ColorSetting | undefined) => {
39-
setStyle({ color, backgroundColor });
40-
}, [backgroundColor, setStyle]);
59+
const style = { color, backgroundColor, font };
60+
setStyle(style);
61+
setFieldValue("interface.styleOverrides", style);
62+
}, [backgroundColor, font, setFieldValue, setStyle]);
4163

4264
const setBgColor = useCallback((backgroundColor: ColorSetting | undefined) => {
43-
setStyle({ color, backgroundColor });
44-
}, [color, setStyle]);
65+
const style = { color, backgroundColor, font };
66+
setStyle(style);
67+
setFieldValue("interface.styleOverrides", style);
68+
}, [color, font, setFieldValue, setStyle]);
69+
70+
const setFont = useCallback((font: string) => {
71+
const style = { color, backgroundColor, font: font === "Default" ? undefined : font };
72+
setStyle(style);
73+
setFieldValue("interface.styleOverrides", style);
74+
}, [backgroundColor, color, setFieldValue, setStyle]);
4575

4676
const defaultColor = theme.colorScheme === "dark"
4777
? { color: "dark", shade: 0 }
@@ -52,20 +82,25 @@ export function InterfaceSettigsPanel<V extends InterfaceFormValues>(props: { fo
5282
: { color: "gray", shade: 0 };
5383

5484
return (
55-
<Grid>
85+
<Grid align="center">
86+
<Grid.Col span={2}>
87+
Font
88+
</Grid.Col>
89+
<Grid.Col span={4}>
90+
<NativeSelect data={systemFonts} value={font} onChange={(e) => { setFont(e.currentTarget.value); }} />
91+
</Grid.Col>
5692
<Grid.Col span={2}>
57-
Text
93+
Text color
5894
</Grid.Col>
5995
<Grid.Col span={1}>
6096
<ColorChooser value={color ?? defaultColor} onChange={setTextColor} />
6197
</Grid.Col>
6298
<Grid.Col span={2}>
63-
Bakground
99+
Background
64100
</Grid.Col>
65101
<Grid.Col span={1}>
66102
<ColorChooser value={backgroundColor ?? defaultBg} onChange={setBgColor} />
67103
</Grid.Col>
68-
<Grid.Col span={6} />
69104
<Grid.Col>
70105
<Checkbox label="Skip add torrent dialog"
71106
{...props.form.getInputProps("interface.skipAddDialog", { type: "checkbox" })} />

src/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ interface Settings {
120120
styleOverrides: {
121121
color?: ColorSetting,
122122
backgroundColor?: ColorSetting,
123+
font?: string,
123124
},
124125
},
125126
}

src/themehooks.tsx

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import { useToggle } from "@mantine/hooks";
2020
import type { ColorSetting } from "components/colorswatch";
2121
import { ConfigContext } from "config";
22-
import React, { useContext, useEffect, useMemo, useState } from "react";
22+
import React, { useContext, useEffect, useMemo } from "react";
2323

2424
interface FontsizeContextValue {
2525
value: number,
@@ -72,25 +72,11 @@ export function useFontSize() {
7272
interface GlobalStyleOverrides {
7373
color?: ColorSetting,
7474
backgroundColor?: ColorSetting,
75+
font?: string,
7576
setStyle: React.Dispatch<Omit<GlobalStyleOverrides, "setStyle">>,
7677
}
7778

78-
const GlobalStyleOverridesContext = React.createContext<GlobalStyleOverrides>({ setStyle: () => { } });
79-
80-
export function GlobalStyleOverridesContextProvider(props: React.PropsWithChildren) {
81-
const config = useContext(ConfigContext);
82-
const [style, setStyle] = useState(config.values.interface.styleOverrides);
83-
84-
useEffect(() => {
85-
config.values.interface.styleOverrides = style;
86-
}, [config, style]);
87-
88-
return (
89-
<GlobalStyleOverridesContext.Provider value={{ ...style, setStyle }}>
90-
{props.children}
91-
</GlobalStyleOverridesContext.Provider>
92-
);
93-
}
79+
export const GlobalStyleOverridesContext = React.createContext<GlobalStyleOverrides>({ setStyle: () => { } });
9480

9581
export function useGlobalStyleOverrides() {
9682
return useContext(GlobalStyleOverridesContext);

0 commit comments

Comments
 (0)