mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-22 05:19:08 +02:00
* [client] Add RTL layout support to the desktop UI <html dir> follows the active language, Radix primitives get the matching dir, physical spacing/positioning uses logical utilities, and directional icons, animations, arrow-key navigation and tooltip sides flip in RTL. * [client] Address RTL review feedback Force LTR with isolation for monospace values, let truncated names take their direction from their content, and keep the profile name field in the UI direction. * [client] Keep translated monospace labels in their own direction The forced-LTR rule for monospace values now skips elements with an explicit dir, translated development labels use dir=auto, and monospace values rendered through TruncatedText opt into LTR. --------- Co-authored-by: Edward <43848523+thomashacker@users.noreply.github.com>
88 lines
2.9 KiB
TypeScript
88 lines
2.9 KiB
TypeScript
import { type ReactNode } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import * as Dialog from "@/components/dialog/Dialog";
|
|
import { Button } from "@/components/buttons/Button";
|
|
import { DialogHeading } from "@/components/dialog/DialogHeading";
|
|
import { DialogDescription } from "@/components/dialog/DialogDescription";
|
|
import { DialogActions } from "@/components/dialog/DialogActions";
|
|
|
|
type ConfirmModalProps = {
|
|
open: boolean;
|
|
title: ReactNode;
|
|
description: ReactNode;
|
|
confirmLabel: string;
|
|
cancelLabel?: string;
|
|
danger?: boolean;
|
|
busy?: boolean;
|
|
cancellable?: boolean;
|
|
onConfirm: () => void;
|
|
onCancel: () => void;
|
|
};
|
|
|
|
export const ConfirmModal = ({
|
|
open,
|
|
title,
|
|
description,
|
|
confirmLabel,
|
|
cancelLabel,
|
|
danger = false,
|
|
busy = false,
|
|
cancellable,
|
|
onConfirm,
|
|
onCancel,
|
|
}: ConfirmModalProps) => {
|
|
const { t } = useTranslation();
|
|
const resolvedCancel = cancelLabel ?? t("common.cancel");
|
|
const canCancel = cancellable ?? !busy;
|
|
|
|
const srTitle = typeof title === "string" ? title : undefined;
|
|
const srDescription = typeof description === "string" ? description : undefined;
|
|
|
|
return (
|
|
<Dialog.Root
|
|
open={open}
|
|
onOpenChange={(next) => {
|
|
if (!next && canCancel) onCancel();
|
|
}}
|
|
>
|
|
<Dialog.Content
|
|
maxWidthClass={"max-w-sm"}
|
|
showClose={false}
|
|
className={"py-5"}
|
|
srTitle={srTitle}
|
|
srDescription={srDescription}
|
|
onOpenAutoFocus={(e) => e.preventDefault()}
|
|
>
|
|
<div className={"flex flex-col gap-5 px-5"}>
|
|
<div className={"flex flex-col gap-1 ps-1"}>
|
|
<DialogHeading align={"start"}>{title}</DialogHeading>
|
|
<DialogDescription align={"start"} className={"whitespace-pre-line"}>
|
|
{description}
|
|
</DialogDescription>
|
|
</div>
|
|
|
|
<DialogActions className={"flex-row justify-end gap-2.5"}>
|
|
<Button
|
|
variant={"secondary"}
|
|
size={"sm"}
|
|
disabled={!canCancel}
|
|
onClick={onCancel}
|
|
>
|
|
{resolvedCancel}
|
|
</Button>
|
|
<Button
|
|
autoFocus
|
|
variant={danger ? "danger" : "primary"}
|
|
size={"sm"}
|
|
loading={busy}
|
|
onClick={onConfirm}
|
|
>
|
|
{confirmLabel}
|
|
</Button>
|
|
</DialogActions>
|
|
</div>
|
|
</Dialog.Content>
|
|
</Dialog.Root>
|
|
);
|
|
};
|