Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion frontend/.oxlintrc-plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
"solid/no-array-handlers": "error",
"solid/no-destructure": "error",
"solid/no-innerhtml": "error",
"solid/no-proxy-apis": "error",
"solid/no-react-deps": "error",
"solid/no-react-specific-props": "error",
"solid/no-unknown-namespaces": "error",
Expand Down
23 changes: 16 additions & 7 deletions frontend/__tests__/components/Button.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,16 @@ describe("Button component", () => {
onClick={() => {
//
}}
icon="fa-test"
fa={{
icon: "keyboard",
}}
/>
));

const icon = container.querySelector("i");
expect(icon).toBeTruthy();
expect(icon?.className).toContain("icon");
expect(icon?.className).toContain("fa-test");
expect(icon?.className).toContain("fas");
expect(icon?.className).toContain("fa-keyboard");
});

it("applies fa-fw class when text is missing", () => {
Expand All @@ -67,7 +69,10 @@ describe("Button component", () => {
onClick={() => {
//
}}
icon="fa-test"
fa={{
icon: "keyboard",
fixedWidth: true,
}}
/>
));

Expand All @@ -81,9 +86,11 @@ describe("Button component", () => {
onClick={() => {
//
}}
icon="fa-test"
fa={{
fixedWidth: true,
icon: "keyboard",
}}
text="Hello"
fixedWidthIcon
/>
));

Expand All @@ -97,7 +104,9 @@ describe("Button component", () => {
onClick={() => {
//
}}
icon="fa-test"
fa={{
icon: "keyboard",
}}
text="Hello"
/>
));
Expand Down
2 changes: 1 addition & 1 deletion frontend/__tests__/components/ScrollToTop.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ describe("ScrollToTop", () => {

expect(container).toHaveClass("content-grid", "ScrollToTop");
expect(button).toHaveClass("breakout");
expect(button).toContainHTML(`<i class="fas fa-angle-double-up"></i>`);
expect(button.querySelector("i")).toHaveClass("fas", "fa-angle-double-up");
});

it("renders invisible when scrollY is 0", () => {
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/ts/components/common/AsyncContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as Notifications from "../../elements/notifications";
import { createErrorMessage } from "../../utils/misc";

import { Conditional } from "./Conditional";
import { Fa } from "./Fa";

export default function AsyncContent<T>(
props: {
Expand Down Expand Up @@ -51,7 +52,7 @@ export default function AsyncContent<T>(
<>
<Show when={p.showLoader && props.resource.loading}>
<div class="preloader text-main p-4 text-center text-2xl">
<i class="fas fa-fw fa-spin fa-circle-notch"></i>
<Fa icon="circle-notch" fixedWidth spin />
</div>
</Show>
{p.children(value())}
Expand All @@ -65,7 +66,7 @@ export default function AsyncContent<T>(
<Suspense
fallback={
<div class="preloader text-main p-4 text-center text-2xl">
<i class="fas fa-fw fa-spin fa-circle-notch"></i>
<Fa icon="circle-notch" fixedWidth spin />
</div>
}
>
Expand Down
17 changes: 4 additions & 13 deletions frontend/src/ts/components/common/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { JSXElement, Show } from "solid-js";

import { Conditional } from "./Conditional";
import { Fa, FaProps } from "./Fa";

type BaseProps = {
text?: string;
icon?: string;
iconScale?: number;
fixedWidthIcon?: boolean;
fa?: FaProps;
class?: string;
type?: "text" | "button";
children?: JSXElement;
Expand All @@ -29,16 +28,8 @@ export function Button(props: ButtonProps | AnchorProps): JSXElement {

const content = (
<>
<Show when={props.icon !== undefined}>
<i
class={`icon ${props.icon}`}
style={{
"font-size": `${props.iconScale ?? 1}em`,
}}
classList={{
"fa-fw": props.text === undefined || props.fixedWidthIcon === true,
}}
></i>
<Show when={props.fa !== undefined}>
<Fa {...(props.fa as FaProps)} />
</Show>
<Show when={props.text !== undefined}>{props.text}</Show>
{props.children}
Expand Down
28 changes: 28 additions & 0 deletions frontend/src/ts/components/common/Fa.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { JSXElement } from "solid-js";

import { FaObject } from "../../types/font-awesome";

export type FaProps = {
fixedWidth?: boolean;
spin?: boolean;
size?: number;
} & FaObject;

export function Fa(props: FaProps): JSXElement {
const variant = (): string => props.variant ?? "solid";
return (
<i
class={`fa-${props.icon}`}
classList={{
["fas"]: variant() === "solid",
["far"]: variant() === "regular",
["fab"]: variant() === "brand",
["fa-fw"]: props.fixedWidth === true,
["fa-spin"]: props.spin === true,
}}
style={{
"font-size": props.size !== undefined ? `${props.size}em` : undefined,
}}
></i>
);
}
50 changes: 34 additions & 16 deletions frontend/src/ts/components/layout/footer/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,58 +28,76 @@ export function Footer(): JSXElement {
<Button
type="text"
text="contact"
icon="fas fa-envelope"
fixedWidthIcon
fa={{
icon: "envelope",
fixedWidth: true,
}}
onClick={() => showModal("Contact")}
/>
<Button
type="text"
text="support"
icon="fas fa-donate"
fixedWidthIcon
fa={{
icon: "donate",
fixedWidth: true,
}}
onClick={() => showModal("Support")}
/>
<Button
type="text"
text="github"
icon="fas fa-code"
fixedWidthIcon
fa={{
icon: "code",
fixedWidth: true,
}}
href="https://github.com/monkeytypegame/monkeytype"
/>
<Button
type="text"
text="discord"
icon="fab fa-discord"
fixedWidthIcon
fa={{
icon: "discord",
variant: "brand",
fixedWidth: true,
}}
href="https://www.discord.gg/monkeytype"
/>
<Button
type="text"
text="twitter"
icon="fab fa-twitter"
fixedWidthIcon
fa={{
icon: "twitter",
variant: "brand",
fixedWidth: true,
}}
href="https://x.com/monkeytype"
/>
<Button
type="text"
text="terms"
icon="fas fa-file-contract"
fixedWidthIcon
fa={{
icon: "file-contract",
fixedWidth: true,
}}
href="/terms-of-service.html"
/>
<Button
href="/security-policy.html"
type="text"
text="security"
icon="fas fa-shield-alt"
fixedWidthIcon
fa={{
icon: "shield-alt",
fixedWidth: true,
}}
/>
<Button
href="/privacy-policy.html"
type="text"
text="privacy"
icon="fas fa-lock"
fixedWidthIcon
fa={{
icon: "lock",
fixedWidth: true,
}}
/>
</div>
<div class="flex flex-col items-end text-right lg:flex-row">
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/ts/components/layout/footer/ScrollToTop.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { JSXElement, createSignal, onMount, onCleanup } from "solid-js";

import { getActivePage } from "../../../signals/core";
import { Fa } from "../../common/Fa";

export function ScrollToTop(): JSXElement {
const [visible, setVisible] = createSignal(false);
Expand Down Expand Up @@ -42,7 +43,7 @@ export function ScrollToTop(): JSXElement {
});
}}
>
<i class="fas fa-angle-double-up"></i>
<Fa icon="angle-double-up" />
</button>
</div>
);
Expand Down
7 changes: 5 additions & 2 deletions frontend/src/ts/components/layout/footer/ThemeIndicator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import * as DB from "../../../db";
import * as Notifications from "../../../elements/notifications";
import { isAuthenticated } from "../../../firebase";
import { getThemeIndicator } from "../../../signals/core";
import { Fa } from "../../common/Fa";

export function ThemeIndicator(): JSXElement {
const handleClick = (e: MouseEvent): void => {
Expand Down Expand Up @@ -41,9 +42,11 @@ export function ThemeIndicator(): JSXElement {
>
<div class="relative">
<Show when={getThemeIndicator().isFavorite}>
<i class="fas fa-star bg-bg absolute top-[-0.5em] right-[-0.5em] rounded-full p-[0.25em] text-[0.5em]"></i>
<div class="bg-bg absolute top-[-0.5em] right-[-0.5em] flex rounded-full p-[0.25em]">
<Fa icon="star" size={0.5} />
</div>
</Show>
<i class="fas fa-fw fa-palette"></i>
<Fa icon="palette" fixedWidth />
</div>
<div class="text">{getThemeIndicator().text}</div>
</button>
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/ts/components/layout/footer/VersionButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { lastSeenServerCompatibility } from "../../../ape/adapters/ts-rest-adapt
import { getVersion } from "../../../signals/core";
import { showModal } from "../../../stores/modals";
import { isDevEnvironment } from "../../../utils/misc";
import { Fa } from "../../common/Fa";

export function VersionButton(): JSXElement {
const [indicatorVisible, setIndicatorVisible] = createSignal(true);
Expand Down Expand Up @@ -45,7 +46,7 @@ export function VersionButton(): JSXElement {

return (
<button type="button" class="textButton flex" onClick={handleClick}>
<i class="fas fa-fw fa-code-branch"></i>
<Fa icon="code-branch" fixedWidth />
<div class="text">{getVersionText()}</div>
<Show when={showNewIndicator()}>
<div
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/ts/components/layout/overlays/Banners.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
} from "../../../stores/banners";
import { cn } from "../../../utils/cn";
import { Conditional } from "../../common/Conditional";
import { Fa } from "../../common/Fa";

function Banner(props: BannerType): JSXElement {
const remove = (): void => {
Expand Down Expand Up @@ -65,7 +66,7 @@ function Banner(props: BannerType): JSXElement {
remove();
}}
>
<i class="fas fa-fw fa-times"></i>
<Fa icon="times" fixedWidth />
</button>
}
/>
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/ts/components/layout/overlays/Overlays.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { JSXElement } from "solid-js";
import { getIsScreenshotting } from "../../../signals/core";
import { showModal } from "../../../stores/modals";
import { cn } from "../../../utils/cn";
import { Fa } from "../../common/Fa";
import { ScrollToTop } from "../footer/ScrollToTop";

import { Banners } from "./Banners";
Expand All @@ -28,7 +29,7 @@ export function Overlays(): JSXElement {
}}
tabIndex="-1"
>
<i class="fas fa-terminal"></i>
<Fa icon="terminal" />
</button>
<Banners />
<MediaQueryDebugger />
Expand Down
Loading
Loading