diff --git a/FrontEnd/src/common.ts b/FrontEnd/src/common.ts index b819d209..965f9933 100644 --- a/FrontEnd/src/common.ts +++ b/FrontEnd/src/common.ts @@ -1,33 +1,10 @@ -import { TFunction } from "i18next"; - // This error is thrown when ui goes wrong with bad logic. // Such as a variable should not be null, but it does. // This error should never occur. If it does, it indicates there is some logic bug in codes. export class UiLogicError extends Error {} -export type I18nText = - | string - | { type: "custom"; value: string } - | { type: "i18n"; value: string }; - -export function convertI18nText(text: I18nText, t: TFunction): string; -export function convertI18nText( - text: I18nText | null | undefined, - t: TFunction -): string | null; -export function convertI18nText( - text: I18nText | null | undefined, - t: TFunction -): string | null { - if (text == null) { - return null; - } else if (typeof text === "string") { - return t(text); - } else if (text.type === "i18n") { - return t(text.value); - } else { - return text.value; - } -} - export const highlightTimelineUsername = "crupest"; + +export type { I18nText } from "./i18n"; +export { c, convertI18nText } from "./i18n"; +export { default as useC } from "./utilities/hooks/use-c"; diff --git a/FrontEnd/src/i18n.ts b/FrontEnd/src/i18n.ts index 59b6f64a..3166ec3c 100644 --- a/FrontEnd/src/i18n.ts +++ b/FrontEnd/src/i18n.ts @@ -74,3 +74,41 @@ if (module.hot) { } export default i18n; + +export type I18nText = + | string + | { type: "text" | "custom"; value: string } + | { type: "i18n"; value: string }; + +type T = typeof i18n.t; + +export function convertI18nText(text: I18nText, t: T): string; +export function convertI18nText( + text: I18nText | null | undefined, + t: T, +): string | null; +export function convertI18nText( + text: I18nText | null | undefined, + t: T, +): string | null { + if (text == null) { + return null; + } else if (typeof text === "string") { + return t(text); + } else if (text.type === "i18n") { + return t(text.value); + } else { + return text.value; + } +} + +export interface C { + (text: I18nText): string; + (text: I18nText | null | undefined): string | null; +} + +export function createC(t: T): C { + return ((text) => convertI18nText(text, t)) as C; +} + +export const c = createC(i18n.t); diff --git a/FrontEnd/src/utilities/hooks/use-c.ts b/FrontEnd/src/utilities/hooks/use-c.ts new file mode 100644 index 00000000..96195ae2 --- /dev/null +++ b/FrontEnd/src/utilities/hooks/use-c.ts @@ -0,0 +1,7 @@ +import { useTranslation } from "react-i18next"; +import { C, createC } from "../../i18n"; + +export default function useC(ns?: string): C { + const { t } = useTranslation(ns); + return createC(t); +} diff --git a/FrontEnd/src/views/common/button/Button.tsx b/FrontEnd/src/views/common/button/Button.tsx index c5976909..be605328 100644 --- a/FrontEnd/src/views/common/button/Button.tsx +++ b/FrontEnd/src/views/common/button/Button.tsx @@ -1,43 +1,47 @@ -import * as React from "react"; +import { ComponentPropsWithoutRef, Ref } from "react"; import classNames from "classnames"; -import { useTranslation } from "react-i18next"; -import { convertI18nText, I18nText } from "@/common"; +import { I18nText, useC } from "@/common"; import { PaletteColorType } from "@/palette"; import "./Button.css"; -function _Button( - props: { - color?: PaletteColorType; - text?: I18nText; - outline?: boolean; - } & React.ComponentPropsWithoutRef<"button">, - ref: React.ForwardedRef -): JSX.Element { - const { t } = useTranslation(); +interface ButtonProps extends ComponentPropsWithoutRef<"button"> { + color?: PaletteColorType; + text?: I18nText; + outline?: boolean; + buttonRef?: Ref | null; +} - const { color, text, outline, className, children, ...otherProps } = props; +export default function Button(props: ButtonProps) { + const { + buttonRef, + color, + text, + outline, + className, + children, + ...otherProps + } = props; if (text != null && children != null) { console.warn("You can't set both text and children props."); } + const c = useC(); + return ( ); } - -const Button = React.forwardRef(_Button); -export default Button; diff --git a/FrontEnd/src/views/common/button/FlatButton.tsx b/FrontEnd/src/views/common/button/FlatButton.tsx index b42c5b3a..49912b68 100644 --- a/FrontEnd/src/views/common/button/FlatButton.tsx +++ b/FrontEnd/src/views/common/button/FlatButton.tsx @@ -1,41 +1,37 @@ -import * as React from "react"; -import { useTranslation } from "react-i18next"; +import { ComponentPropsWithoutRef, Ref } from "react"; import classNames from "classnames"; -import { convertI18nText, I18nText } from "@/common"; +import { I18nText, useC } from "@/common"; import { PaletteColorType } from "@/palette"; import "./FlatButton.css"; -function _FlatButton( - props: { - color?: PaletteColorType; - text?: I18nText; - } & React.ComponentPropsWithoutRef<"button">, - ref: React.ForwardedRef -): React.ReactElement | null { - const { t } = useTranslation(); +interface FlatButtonProps extends ComponentPropsWithoutRef<"button"> { + color?: PaletteColorType; + text?: I18nText; + buttonRef?: Ref | null; +} - const { color, text, className, children, ...otherProps } = props; +export default function FlatButton(props: FlatButtonProps) { + const { color, text, className, children, buttonRef, ...otherProps } = props; if (text != null && children != null) { console.warn("You can't set both text and children props."); } + const c = useC(); + return ( ); } - -const FlatButton = React.forwardRef(_FlatButton); -export default FlatButton; diff --git a/FrontEnd/src/views/common/button/IconButton.css b/FrontEnd/src/views/common/button/IconButton.css index ef4dca00..45fb103c 100644 --- a/FrontEnd/src/views/common/button/IconButton.css +++ b/FrontEnd/src/views/common/button/IconButton.css @@ -1,7 +1,8 @@ .cru-icon-button { color: var(--cru-theme-color); font-size: 1.4rem; - cursor: pointer; + background: none; + border: none; } .cru-icon-button.large { diff --git a/FrontEnd/src/views/common/button/IconButton.tsx b/FrontEnd/src/views/common/button/IconButton.tsx index 3ba56277..652a8b09 100644 --- a/FrontEnd/src/views/common/button/IconButton.tsx +++ b/FrontEnd/src/views/common/button/IconButton.tsx @@ -1,21 +1,21 @@ -import * as React from "react"; +import { ComponentPropsWithoutRef } from "react"; import classNames from "classnames"; import { PaletteColorType } from "@/palette"; import "./IconButton.css"; -export interface IconButtonProps extends React.ComponentPropsWithRef<"i"> { +interface IconButtonProps extends ComponentPropsWithoutRef<"i"> { icon: string; color?: PaletteColorType; large?: boolean; } -export default function IconButton(props: IconButtonProps): JSX.Element { +export default function IconButton(props: IconButtonProps) { const { icon, color, className, large, ...otherProps } = props; return ( - void; open: boolean; - children?: React.ReactNode; + children?: ReactNode; disableCloseOnClickOnOverlay?: boolean; } -export default function Dialog(props: DialogProps): React.ReactElement | null { +export default function Dialog(props: DialogProps) { const { open, onClose, children, disableCloseOnClickOnOverlay } = props; return ReactDOM.createPortal( @@ -24,7 +30,7 @@ export default function Dialog(props: DialogProps): React.ReactElement | null { >
{ @@ -34,13 +40,12 @@ export default function Dialog(props: DialogProps): React.ReactElement | null { >
e.stopPropagation()} + onPointerDown={(e) => e.stopPropagation()} > {children}
, - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - document.getElementById("portal")! + portalElement, ); }