Refactor PreferenceRadioGroup to use react-aria-components

This commit is contained in:
Kalle 2025-03-13 17:03:05 +02:00
parent 6ab8ea54d2
commit d533dffcf6
2 changed files with 89 additions and 75 deletions

View File

@ -0,0 +1,87 @@
import clsx from "clsx";
import { Radio, RadioGroup } from "react-aria-components";
import { useTranslation } from "react-i18next";
import type { Preference } from "~/db/tables";
import { preferenceEmojiUrl } from "~/utils/urls";
export function PreferenceRadioGroup({
preference,
onPreferenceChange,
"aria-label": ariaLabel,
}: {
preference?: Preference;
onPreferenceChange: (preference: Preference & "NEUTRAL") => void;
"aria-label": string;
}) {
const { t } = useTranslation(["q"]);
return (
<RadioGroup
value={preference ?? "NEUTRAL"}
onChange={(newPreference) =>
onPreferenceChange(newPreference as Preference & "NEUTRAL")
}
className="stack horizontal xs"
aria-label={ariaLabel}
orientation="horizontal"
>
<Radio value="AVOID" aria-label="Avoid the mode">
{({ isSelected, isHovered, isFocusVisible }) => (
<span
className={clsx("q-settings__radio", {
"q-settings__radio__checked": isSelected,
"q-settings__radio__hovered": isHovered,
"q-settings__radio__focus-visible": isFocusVisible,
})}
>
<img
src={preferenceEmojiUrl("AVOID")}
className="q-settings__radio__emoji"
width={18}
alt="Avoid emoji"
/>
{t("q:settings.maps.avoid")}
</span>
)}
</Radio>
<Radio value="NEUTRAL" aria-label="Neutral towards the mode">
{({ isSelected, isHovered, isFocusVisible }) => (
<span
className={clsx("q-settings__radio", {
"q-settings__radio__checked": isSelected,
"q-settings__radio__hovered": isHovered,
"q-settings__radio__focus-visible": isFocusVisible,
})}
>
<img
src={preferenceEmojiUrl()}
className="q-settings__radio__emoji"
width={18}
alt="Neutral emoji"
/>
{t("q:settings.maps.neutral")}
</span>
)}
</Radio>
<Radio value="PREFER" aria-label="Prefer the mode">
{({ isSelected, isHovered, isFocusVisible }) => (
<span
className={clsx("q-settings__radio", {
"q-settings__radio__checked": isSelected,
"q-settings__radio__hovered": isHovered,
"q-settings__radio__focus-visible": isFocusVisible,
})}
>
<img
src={preferenceEmojiUrl("PREFER")}
className="q-settings__radio__emoji"
width={18}
alt="Prefer emoji"
/>
{t("q:settings.maps.prefer")}
</span>
)}
</Radio>
</RadioGroup>
);
}

View File

@ -1,11 +1,9 @@
import { RadioGroup } from "@headlessui/react";
import type {
ActionFunctionArgs,
LoaderFunctionArgs,
MetaFunction,
} from "@remix-run/node";
import { useFetcher, useLoaderData } from "@remix-run/react";
import clsx from "clsx";
import * as React from "react";
import { useState } from "react";
import { useTranslation } from "react-i18next";
@ -45,7 +43,6 @@ import {
SENDOUQ_PAGE,
SENDOUQ_SETTINGS_PAGE,
navIconUrl,
preferenceEmojiUrl,
soundPath,
} from "~/utils/urls";
import { BANNED_MAPS } from "../banned-maps";
@ -58,6 +55,7 @@ import { settingsActionSchema } from "../q-settings-schemas.server";
import "../q-settings.css";
import { SendouSwitch } from "~/components/elements/Switch";
import { metaTags } from "~/utils/remix";
import { PreferenceRadioGroup } from "../components/PreferenceRadioGroup";
export const handle: SendouRouteHandle = {
i18n: ["q"],
@ -262,6 +260,7 @@ function MapPicker() {
preference,
})
}
aria-label={`Select preference towards ${modeShort}`}
/>
</div>
);
@ -321,78 +320,6 @@ function MapPicker() {
);
}
function PreferenceRadioGroup({
preference,
onPreferenceChange,
}: {
preference?: Preference;
onPreferenceChange: (preference: Preference & "NEUTRAL") => void;
}) {
const { t } = useTranslation(["q"]);
return (
<RadioGroup
value={preference ?? "NEUTRAL"}
onChange={(newPreference) =>
onPreferenceChange(newPreference as Preference & "NEUTRAL")
}
className="stack horizontal xs"
>
<RadioGroup.Option value="AVOID">
{({ checked }) => (
<span
className={clsx("q-settings__radio", {
"q-settings__radio__checked": checked,
})}
>
<img
src={preferenceEmojiUrl("AVOID")}
className="q-settings__radio__emoji"
width={18}
alt="Avoid emoji"
/>
{t("q:settings.maps.avoid")}
</span>
)}
</RadioGroup.Option>
<RadioGroup.Option value="NEUTRAL">
{({ checked }) => (
<span
className={clsx("q-settings__radio", {
"q-settings__radio__checked": checked,
})}
>
<img
src={preferenceEmojiUrl()}
className="q-settings__radio__emoji"
width={18}
alt="Neutral emoji"
/>
{t("q:settings.maps.neutral")}
</span>
)}
</RadioGroup.Option>
<RadioGroup.Option value="PREFER">
{({ checked }) => (
<span
className={clsx("q-settings__radio", {
"q-settings__radio__checked": checked,
})}
>
<img
src={preferenceEmojiUrl("PREFER")}
className="q-settings__radio__emoji"
width={18}
alt="Prefer emoji"
/>
{t("q:settings.maps.prefer")}
</span>
)}
</RadioGroup.Option>
</RadioGroup>
);
}
function VoiceChat() {
const { t } = useTranslation(["common", "q"]);
const fetcher = useFetcher();