Skip to content

Commit

Permalink
feat: allow switching theme fonts
Browse files Browse the repository at this point in the history
  • Loading branch information
aradzie committed Apr 7, 2024
1 parent 27157a9 commit fdd9b3b
Show file tree
Hide file tree
Showing 24 changed files with 154 additions and 168 deletions.
10 changes: 10 additions & 0 deletions packages/keybr-fonts/lib/index.less
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,13 @@
--monospace-font-family: "Ubuntu Mono", monospace;
--value-font-family: "Ubuntu Mono", monospace;
}

html[data-font="opensans"] {
--default-font-family: "Open Sans", sans-serif;
--header-font-family: "Open Sans", sans-serif;
}

html[data-font="spectral"] {
--default-font-family: "Spectral", sans-serif;
--header-font-family: "Spectral", sans-serif;
}
53 changes: 23 additions & 30 deletions packages/keybr-lnf-browser/lib/provider.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ import { type ReactNode } from "react";
import { ThemeProvider } from "./provider.tsx";

test.beforeEach(() => {
document.documentElement.dataset["theme"] = "dark";
document.documentElement.dataset["text"] = "huge";
document.documentElement.dataset["color"] = "dark";
document.documentElement.dataset["font"] = "spectral";

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

test.afterEach(() => {
document.documentElement.dataset["theme"] = "";
document.documentElement.dataset["text"] = "";
document.documentElement.dataset["color"] = "";
document.documentElement.dataset["font"] = "";
});

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

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

// Act.

await userEvent.click(r.getByText("light theme"));
await userEvent.click(r.getByText("light"));

// Assert.

t.is(
document.cookie,
"prefs=%7B%22themeName%22%3A%22light%22%2C%22textSize%22%3A%22huge%22%7D",
"prefs=%7B%22color%22%3A%22light%22%2C%22font%22%3A%22spectral%22%7D",
);
t.is(document.documentElement.dataset["theme"], "light");
t.is(document.documentElement.dataset["text"], "huge");
t.is(document.documentElement.dataset["color"], "light");
t.is(document.documentElement.dataset["font"], "spectral");

// Act.

await userEvent.click(r.getByText("normal text size"));
await userEvent.click(r.getByText("opensans"));

// Assert.

t.is(
document.cookie,
"prefs=%7B%22themeName%22%3A%22light%22%2C%22textSize%22%3A%22normal%22%7D",
"prefs=%7B%22color%22%3A%22light%22%2C%22font%22%3A%22opensans%22%7D",
);
t.is(document.documentElement.dataset["theme"], "light");
t.is(document.documentElement.dataset["text"], "normal");
t.is(document.documentElement.dataset["color"], "light");
t.is(document.documentElement.dataset["font"], "opensans");

// Cleanup.

Expand Down Expand Up @@ -94,38 +94,31 @@ function Switcher(): ReactNode {
<div>
<button
onClick={() => {
ctl.switchTheme("light");
ctl.switchColor("light");
}}
>
light theme
light
</button>
<button
onClick={() => {
ctl.switchTheme("dark");
ctl.switchColor("dark");
}}
>
dark theme
dark
</button>
<button
onClick={() => {
ctl.switchTextSize("normal");
ctl.switchFont("opensans");
}}
>
normal text size
opensans
</button>
<button
onClick={() => {
ctl.switchTextSize("large");
ctl.switchFont("spectral");
}}
>
large text size
</button>
<button
onClick={() => {
ctl.switchTextSize("huge");
}}
>
huge text size
spectral
</button>
</div>
);
Expand Down
48 changes: 24 additions & 24 deletions packages/keybr-lnf-browser/lib/provider.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Cookie, SetCookie } from "@fastr/headers";
import {
TEXT_SIZES,
type TextSize,
type ColorName,
COLORS,
type FontName,
FONTS,
ThemeContext,
type ThemeName,
ThemePrefs,
THEMES,
} from "@keybr/lnf";
import { Component, type ReactNode } from "react";
import { installPolyfills } from "./fullscreen-polyfill.ts";
Expand All @@ -19,15 +19,15 @@ type Props = {

type State = {
readonly fullscreenState: boolean | null;
readonly themeName: ThemeName;
readonly textSize: TextSize;
readonly color: ColorName;
readonly font: FontName;
};

export class ThemeProvider extends Component<Props, State> {
override state: State = {
fullscreenState: false,
themeName: "light",
textSize: "normal",
color: "light",
font: "opensans",
};

override componentDidMount(): void {
Expand Down Expand Up @@ -55,16 +55,16 @@ export class ThemeProvider extends Component<Props, State> {
}

override render(): ReactNode {
const { fullscreenState, themeName, textSize } = this.state;
const { fullscreenState, color, font } = this.state;
return (
<ThemeContext.Provider
value={{
fullscreenState,
themeName,
textSize,
color,
font,
toggleFullscreen: this.toggleFullscreen,
switchTheme: this.switchTheme,
switchTextSize: this.switchTextSize,
switchColor: this.switchColor,
switchFont: this.switchFont,
}}
>
{this.props.children}
Expand Down Expand Up @@ -92,20 +92,20 @@ export class ThemeProvider extends Component<Props, State> {
}
};

readonly switchTheme = (themeName: ThemeName): void => {
this.setState({ themeName }, () => {
readonly switchColor = (color: ColorName): void => {
this.setState({ color }, () => {
const { state } = this;
const { id } = THEMES.findOption(state.themeName);
document.documentElement.setAttribute("data-theme", id);
const { id } = COLORS.findOption(state.color);
document.documentElement.setAttribute("data-color", id);
storePrefs(new ThemePrefs(state));
});
};

readonly switchTextSize = (textSize: TextSize): void => {
this.setState({ textSize }, () => {
readonly switchFont = (font: FontName): void => {
this.setState({ font }, () => {
const { state } = this;
const { id } = TEXT_SIZES.findOption(state.textSize);
document.documentElement.setAttribute("data-text", id);
const { id } = FONTS.findOption(state.font);
document.documentElement.setAttribute("data-font", id);
storePrefs(new ThemePrefs(state));
});
};
Expand All @@ -117,12 +117,12 @@ function getInitialState(): State {
if (document.fullscreenEnabled) {
fullscreenState = document.fullscreenElement != null;
}
const { themeName, textSize } = ThemePrefs.deserialize(
const { color, font } = ThemePrefs.deserialize(
Cookie.parse(document.cookie).get(ThemePrefs.cookieKey),
);
return { fullscreenState, themeName, textSize };
return { fullscreenState, color: color, font: font };
} catch {
return { fullscreenState: null, themeName: "light", textSize: "normal" };
return { fullscreenState: null, color: "light", font: "opensans" };
}
}

Expand Down
6 changes: 3 additions & 3 deletions packages/keybr-lnf/lib/ThemeSwitcher.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { type ReactNode } from "react";
import * as styles from "./ThemeSwitcher.module.less";
import { FullscreenButton, TextSizeButton, ThemeButton } from "./widgets.tsx";
import { ColorButton, FontButton, FullscreenButton } from "./widgets.tsx";

export function ThemeSwitcher(): ReactNode {
return (
<div className={styles.themeSwitcher}>
<ThemeButton />
<TextSizeButton />
<ColorButton />
<FontButton />
<FullscreenButton />
</div>
);
Expand Down
8 changes: 4 additions & 4 deletions packages/keybr-lnf/lib/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { type ThemeControl } from "./types.ts";

export const ThemeContext = createContext<ThemeControl>({
fullscreenState: null,
themeName: "light",
textSize: "normal",
color: "light",
font: "opensans",
toggleFullscreen: (): void => {},
switchTheme: (): void => {},
switchTextSize: (): void => {},
switchColor: (): void => {},
switchFont: (): void => {},
});

export function useTheme(): ThemeControl {
Expand Down
10 changes: 5 additions & 5 deletions packages/keybr-lnf/lib/lnf.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { TEXT_SIZES, THEMES } from "./options.tsx";
import { COLORS, FONTS } from "./options.tsx";
import { type ThemePrefs } from "./prefs.ts";

export function getTextDataValue(prefs: ThemePrefs): string {
return TEXT_SIZES.findOption(prefs.textSize).id;
export function getColorDataValue(prefs: ThemePrefs): string {
return COLORS.findOption(prefs.color).id;
}

export function getThemeDataValue(prefs: ThemePrefs): string {
return THEMES.findOption(prefs.themeName).id;
export function getFontDataValue(prefs: ThemePrefs): string {
return FONTS.findOption(prefs.font).id;
}
18 changes: 7 additions & 11 deletions packages/keybr-lnf/lib/options.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Icon } from "@keybr/widget";
import { mdiBrightness4, mdiBrightness5 } from "@mdi/js";
import { type TextSizeOption, type ThemeOption } from "./types.ts";
import { type ColorOption, type FontOption } from "./types.ts";

export class OptionList<T extends { id: string }> {
constructor(public readonly all: readonly T[]) {}
Expand All @@ -22,7 +22,7 @@ export class OptionList<T extends { id: string }> {
}
}

export const THEMES = new OptionList<ThemeOption>([
export const COLORS = new OptionList<ColorOption>([
{
id: "light",
icon: <Icon shape={mdiBrightness5} />,
Expand All @@ -35,17 +35,13 @@ export const THEMES = new OptionList<ThemeOption>([
},
]);

export const TEXT_SIZES = new OptionList<TextSizeOption>([
export const FONTS = new OptionList<FontOption>([
{
id: "normal",
title: "Normal Text Size",
id: "opensans",
title: "Open Sans",
},
{
id: "large",
title: "Large Text Size",
},
{
id: "huge",
title: "Huge Text Size",
id: "spectral",
title: "Spectral",
},
]);
25 changes: 12 additions & 13 deletions packages/keybr-lnf/lib/prefs.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type TextSize, type ThemeName } from "./types.ts";
import { type ColorName, type FontName } from "./types.ts";

export class ThemePrefs {
static cookieKey = "prefs";
Expand All @@ -19,28 +19,27 @@ export class ThemePrefs {
return new ThemePrefs(o);
}

readonly themeName: ThemeName;
readonly textSize: TextSize;
readonly color: ColorName;
readonly font: FontName;

constructor(o: unknown) {
let { themeName, textSize }: ThemePrefs = Object(o);
switch (themeName) {
let { color, font }: ThemePrefs = Object(o);
switch (color) {
case "light":
case "dark":
break;
default:
themeName = "light";
color = "light";
break;
}
switch (textSize) {
case "normal":
case "large":
case "huge":
switch (font) {
case "opensans":
case "spectral":
break;
default:
textSize = "normal";
font = "opensans";
}
this.themeName = themeName;
this.textSize = textSize;
this.color = color;
this.font = font;
}
}
Loading

0 comments on commit fdd9b3b

Please sign in to comment.