Skip to content

Commit fdd9b3b

Browse files
committed
feat: allow switching theme fonts
1 parent 27157a9 commit fdd9b3b

24 files changed

+154
-168
lines changed

packages/keybr-fonts/lib/index.less

+10
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,13 @@
2929
--monospace-font-family: "Ubuntu Mono", monospace;
3030
--value-font-family: "Ubuntu Mono", monospace;
3131
}
32+
33+
html[data-font="opensans"] {
34+
--default-font-family: "Open Sans", sans-serif;
35+
--header-font-family: "Open Sans", sans-serif;
36+
}
37+
38+
html[data-font="spectral"] {
39+
--default-font-family: "Spectral", sans-serif;
40+
--header-font-family: "Spectral", sans-serif;
41+
}

packages/keybr-lnf-browser/lib/provider.test.tsx

+23-30
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@ import { type ReactNode } from "react";
66
import { ThemeProvider } from "./provider.tsx";
77

88
test.beforeEach(() => {
9-
document.documentElement.dataset["theme"] = "dark";
10-
document.documentElement.dataset["text"] = "huge";
9+
document.documentElement.dataset["color"] = "dark";
10+
document.documentElement.dataset["font"] = "spectral";
1111

1212
document.cookie =
13-
"prefs=%7B%22themeName%22%3A%22dark%22%2C%22textSize%22%3A%22huge%22%7D";
13+
"prefs=%7B%22color%22%3A%22dark%22%2C%22font%22%3A%22spectral%22%7D";
1414
});
1515

1616
test.afterEach(() => {
17-
document.documentElement.dataset["theme"] = "";
18-
document.documentElement.dataset["text"] = "";
17+
document.documentElement.dataset["color"] = "";
18+
document.documentElement.dataset["font"] = "";
1919
});
2020

2121
test.serial("mount and switch styles", async (t) => {
@@ -32,34 +32,34 @@ test.serial("mount and switch styles", async (t) => {
3232
t.false(document.fullscreenEnabled);
3333
t.is(document.fullscreenElement, null);
3434

35-
t.is(document.documentElement.dataset["theme"], "dark");
36-
t.is(document.documentElement.dataset["text"], "huge");
35+
t.is(document.documentElement.dataset["color"], "dark");
36+
t.is(document.documentElement.dataset["font"], "spectral");
3737

3838
// Act.
3939

40-
await userEvent.click(r.getByText("light theme"));
40+
await userEvent.click(r.getByText("light"));
4141

4242
// Assert.
4343

4444
t.is(
4545
document.cookie,
46-
"prefs=%7B%22themeName%22%3A%22light%22%2C%22textSize%22%3A%22huge%22%7D",
46+
"prefs=%7B%22color%22%3A%22light%22%2C%22font%22%3A%22spectral%22%7D",
4747
);
48-
t.is(document.documentElement.dataset["theme"], "light");
49-
t.is(document.documentElement.dataset["text"], "huge");
48+
t.is(document.documentElement.dataset["color"], "light");
49+
t.is(document.documentElement.dataset["font"], "spectral");
5050

5151
// Act.
5252

53-
await userEvent.click(r.getByText("normal text size"));
53+
await userEvent.click(r.getByText("opensans"));
5454

5555
// Assert.
5656

5757
t.is(
5858
document.cookie,
59-
"prefs=%7B%22themeName%22%3A%22light%22%2C%22textSize%22%3A%22normal%22%7D",
59+
"prefs=%7B%22color%22%3A%22light%22%2C%22font%22%3A%22opensans%22%7D",
6060
);
61-
t.is(document.documentElement.dataset["theme"], "light");
62-
t.is(document.documentElement.dataset["text"], "normal");
61+
t.is(document.documentElement.dataset["color"], "light");
62+
t.is(document.documentElement.dataset["font"], "opensans");
6363

6464
// Cleanup.
6565

@@ -94,38 +94,31 @@ function Switcher(): ReactNode {
9494
<div>
9595
<button
9696
onClick={() => {
97-
ctl.switchTheme("light");
97+
ctl.switchColor("light");
9898
}}
9999
>
100-
light theme
100+
light
101101
</button>
102102
<button
103103
onClick={() => {
104-
ctl.switchTheme("dark");
104+
ctl.switchColor("dark");
105105
}}
106106
>
107-
dark theme
107+
dark
108108
</button>
109109
<button
110110
onClick={() => {
111-
ctl.switchTextSize("normal");
111+
ctl.switchFont("opensans");
112112
}}
113113
>
114-
normal text size
114+
opensans
115115
</button>
116116
<button
117117
onClick={() => {
118-
ctl.switchTextSize("large");
118+
ctl.switchFont("spectral");
119119
}}
120120
>
121-
large text size
122-
</button>
123-
<button
124-
onClick={() => {
125-
ctl.switchTextSize("huge");
126-
}}
127-
>
128-
huge text size
121+
spectral
129122
</button>
130123
</div>
131124
);

packages/keybr-lnf-browser/lib/provider.tsx

+24-24
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { Cookie, SetCookie } from "@fastr/headers";
22
import {
3-
TEXT_SIZES,
4-
type TextSize,
3+
type ColorName,
4+
COLORS,
5+
type FontName,
6+
FONTS,
57
ThemeContext,
6-
type ThemeName,
78
ThemePrefs,
8-
THEMES,
99
} from "@keybr/lnf";
1010
import { Component, type ReactNode } from "react";
1111
import { installPolyfills } from "./fullscreen-polyfill.ts";
@@ -19,15 +19,15 @@ type Props = {
1919

2020
type State = {
2121
readonly fullscreenState: boolean | null;
22-
readonly themeName: ThemeName;
23-
readonly textSize: TextSize;
22+
readonly color: ColorName;
23+
readonly font: FontName;
2424
};
2525

2626
export class ThemeProvider extends Component<Props, State> {
2727
override state: State = {
2828
fullscreenState: false,
29-
themeName: "light",
30-
textSize: "normal",
29+
color: "light",
30+
font: "opensans",
3131
};
3232

3333
override componentDidMount(): void {
@@ -55,16 +55,16 @@ export class ThemeProvider extends Component<Props, State> {
5555
}
5656

5757
override render(): ReactNode {
58-
const { fullscreenState, themeName, textSize } = this.state;
58+
const { fullscreenState, color, font } = this.state;
5959
return (
6060
<ThemeContext.Provider
6161
value={{
6262
fullscreenState,
63-
themeName,
64-
textSize,
63+
color,
64+
font,
6565
toggleFullscreen: this.toggleFullscreen,
66-
switchTheme: this.switchTheme,
67-
switchTextSize: this.switchTextSize,
66+
switchColor: this.switchColor,
67+
switchFont: this.switchFont,
6868
}}
6969
>
7070
{this.props.children}
@@ -92,20 +92,20 @@ export class ThemeProvider extends Component<Props, State> {
9292
}
9393
};
9494

95-
readonly switchTheme = (themeName: ThemeName): void => {
96-
this.setState({ themeName }, () => {
95+
readonly switchColor = (color: ColorName): void => {
96+
this.setState({ color }, () => {
9797
const { state } = this;
98-
const { id } = THEMES.findOption(state.themeName);
99-
document.documentElement.setAttribute("data-theme", id);
98+
const { id } = COLORS.findOption(state.color);
99+
document.documentElement.setAttribute("data-color", id);
100100
storePrefs(new ThemePrefs(state));
101101
});
102102
};
103103

104-
readonly switchTextSize = (textSize: TextSize): void => {
105-
this.setState({ textSize }, () => {
104+
readonly switchFont = (font: FontName): void => {
105+
this.setState({ font }, () => {
106106
const { state } = this;
107-
const { id } = TEXT_SIZES.findOption(state.textSize);
108-
document.documentElement.setAttribute("data-text", id);
107+
const { id } = FONTS.findOption(state.font);
108+
document.documentElement.setAttribute("data-font", id);
109109
storePrefs(new ThemePrefs(state));
110110
});
111111
};
@@ -117,12 +117,12 @@ function getInitialState(): State {
117117
if (document.fullscreenEnabled) {
118118
fullscreenState = document.fullscreenElement != null;
119119
}
120-
const { themeName, textSize } = ThemePrefs.deserialize(
120+
const { color, font } = ThemePrefs.deserialize(
121121
Cookie.parse(document.cookie).get(ThemePrefs.cookieKey),
122122
);
123-
return { fullscreenState, themeName, textSize };
123+
return { fullscreenState, color: color, font: font };
124124
} catch {
125-
return { fullscreenState: null, themeName: "light", textSize: "normal" };
125+
return { fullscreenState: null, color: "light", font: "opensans" };
126126
}
127127
}
128128

packages/keybr-lnf/lib/ThemeSwitcher.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { type ReactNode } from "react";
22
import * as styles from "./ThemeSwitcher.module.less";
3-
import { FullscreenButton, TextSizeButton, ThemeButton } from "./widgets.tsx";
3+
import { ColorButton, FontButton, FullscreenButton } from "./widgets.tsx";
44

55
export function ThemeSwitcher(): ReactNode {
66
return (
77
<div className={styles.themeSwitcher}>
8-
<ThemeButton />
9-
<TextSizeButton />
8+
<ColorButton />
9+
<FontButton />
1010
<FullscreenButton />
1111
</div>
1212
);

packages/keybr-lnf/lib/context.tsx

+4-4
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ import { type ThemeControl } from "./types.ts";
33

44
export const ThemeContext = createContext<ThemeControl>({
55
fullscreenState: null,
6-
themeName: "light",
7-
textSize: "normal",
6+
color: "light",
7+
font: "opensans",
88
toggleFullscreen: (): void => {},
9-
switchTheme: (): void => {},
10-
switchTextSize: (): void => {},
9+
switchColor: (): void => {},
10+
switchFont: (): void => {},
1111
});
1212

1313
export function useTheme(): ThemeControl {

packages/keybr-lnf/lib/lnf.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import { TEXT_SIZES, THEMES } from "./options.tsx";
1+
import { COLORS, FONTS } from "./options.tsx";
22
import { type ThemePrefs } from "./prefs.ts";
33

4-
export function getTextDataValue(prefs: ThemePrefs): string {
5-
return TEXT_SIZES.findOption(prefs.textSize).id;
4+
export function getColorDataValue(prefs: ThemePrefs): string {
5+
return COLORS.findOption(prefs.color).id;
66
}
77

8-
export function getThemeDataValue(prefs: ThemePrefs): string {
9-
return THEMES.findOption(prefs.themeName).id;
8+
export function getFontDataValue(prefs: ThemePrefs): string {
9+
return FONTS.findOption(prefs.font).id;
1010
}

packages/keybr-lnf/lib/options.tsx

+7-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Icon } from "@keybr/widget";
22
import { mdiBrightness4, mdiBrightness5 } from "@mdi/js";
3-
import { type TextSizeOption, type ThemeOption } from "./types.ts";
3+
import { type ColorOption, type FontOption } from "./types.ts";
44

55
export class OptionList<T extends { id: string }> {
66
constructor(public readonly all: readonly T[]) {}
@@ -22,7 +22,7 @@ export class OptionList<T extends { id: string }> {
2222
}
2323
}
2424

25-
export const THEMES = new OptionList<ThemeOption>([
25+
export const COLORS = new OptionList<ColorOption>([
2626
{
2727
id: "light",
2828
icon: <Icon shape={mdiBrightness5} />,
@@ -35,17 +35,13 @@ export const THEMES = new OptionList<ThemeOption>([
3535
},
3636
]);
3737

38-
export const TEXT_SIZES = new OptionList<TextSizeOption>([
38+
export const FONTS = new OptionList<FontOption>([
3939
{
40-
id: "normal",
41-
title: "Normal Text Size",
40+
id: "opensans",
41+
title: "Open Sans",
4242
},
4343
{
44-
id: "large",
45-
title: "Large Text Size",
46-
},
47-
{
48-
id: "huge",
49-
title: "Huge Text Size",
44+
id: "spectral",
45+
title: "Spectral",
5046
},
5147
]);

packages/keybr-lnf/lib/prefs.ts

+12-13
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { type TextSize, type ThemeName } from "./types.ts";
1+
import { type ColorName, type FontName } from "./types.ts";
22

33
export class ThemePrefs {
44
static cookieKey = "prefs";
@@ -19,28 +19,27 @@ export class ThemePrefs {
1919
return new ThemePrefs(o);
2020
}
2121

22-
readonly themeName: ThemeName;
23-
readonly textSize: TextSize;
22+
readonly color: ColorName;
23+
readonly font: FontName;
2424

2525
constructor(o: unknown) {
26-
let { themeName, textSize }: ThemePrefs = Object(o);
27-
switch (themeName) {
26+
let { color, font }: ThemePrefs = Object(o);
27+
switch (color) {
2828
case "light":
2929
case "dark":
3030
break;
3131
default:
32-
themeName = "light";
32+
color = "light";
3333
break;
3434
}
35-
switch (textSize) {
36-
case "normal":
37-
case "large":
38-
case "huge":
35+
switch (font) {
36+
case "opensans":
37+
case "spectral":
3938
break;
4039
default:
41-
textSize = "normal";
40+
font = "opensans";
4241
}
43-
this.themeName = themeName;
44-
this.textSize = textSize;
42+
this.color = color;
43+
this.font = font;
4544
}
4645
}

0 commit comments

Comments
 (0)