mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-07 05:59:06 +02:00
[client] Add RTL layout support to the desktop UI (#8076)
* [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>
This commit is contained in:
@@ -86,13 +86,13 @@ function buildInputClassName(
|
||||
"file:border-0 file:bg-transparent file:text-sm file:font-medium",
|
||||
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2",
|
||||
"disabled:cursor-not-allowed disabled:opacity-40",
|
||||
opts.hasCustomPrefix && "!rounded-l-none !border-l-0",
|
||||
opts.hasSuffix && "!pr-9",
|
||||
opts.hasIcon && "!pl-10",
|
||||
opts.hasCustomPrefix && "!rounded-s-none !border-s-0",
|
||||
opts.hasSuffix && "!pe-9",
|
||||
opts.hasIcon && "!ps-10",
|
||||
"border",
|
||||
opts.readOnly && "!border-nb-gray-800 !bg-nb-gray-910 text-nb-gray-350",
|
||||
opts.showStepper &&
|
||||
"!rounded-r-none [-moz-appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none",
|
||||
"!rounded-e-none [-moz-appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none",
|
||||
opts.className,
|
||||
);
|
||||
}
|
||||
@@ -107,7 +107,7 @@ function InputAffix({
|
||||
<div
|
||||
className={cn(
|
||||
inputVariants({ prefixSuffixVariant: error ? "error" : "default" }),
|
||||
"flex h-[40px] w-auto rounded-l-md bg-white px-3 py-2 text-sm",
|
||||
"flex h-[40px] w-auto rounded-s-md bg-white px-3 py-2 text-sm",
|
||||
"items-center whitespace-nowrap border",
|
||||
disabled && "opacity-40",
|
||||
className,
|
||||
@@ -122,7 +122,7 @@ function InputIconSlot({ icon, disabled }: Readonly<{ icon: ReactNode; disabled?
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"absolute left-0 top-0 flex h-full items-center pl-3 text-xs leading-[0] dark:text-nb-gray-300",
|
||||
"absolute start-0 top-0 flex h-full items-center ps-3 text-xs leading-[0] dark:text-nb-gray-300",
|
||||
disabled && "opacity-40",
|
||||
)}
|
||||
>
|
||||
@@ -138,7 +138,7 @@ function InputSuffixSlot({
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"pointer-events-none absolute right-0 top-0 flex h-full select-none items-center pr-3 text-xs leading-[0] dark:text-nb-gray-300",
|
||||
"pointer-events-none absolute end-0 top-0 flex h-full select-none items-center pe-3 text-xs leading-[0] dark:text-nb-gray-300",
|
||||
disabled && "opacity-30",
|
||||
)}
|
||||
>
|
||||
@@ -157,7 +157,7 @@ function NumberStepper({
|
||||
<div
|
||||
className={cn(
|
||||
"flex h-[40px] shrink-0 flex-col overflow-hidden",
|
||||
"rounded-r-md border border-l-0",
|
||||
"rounded-e-md border border-s-0",
|
||||
"border-neutral-200 bg-white dark:border-nb-gray-700 dark:bg-nb-gray-900",
|
||||
error && "dark:border-red-500",
|
||||
disabled && "pointer-events-none opacity-40",
|
||||
@@ -226,6 +226,7 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(function Input(
|
||||
showPasswordToggle = false,
|
||||
copy = false,
|
||||
id,
|
||||
dir,
|
||||
...props
|
||||
},
|
||||
ref,
|
||||
@@ -336,7 +337,7 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(function Input(
|
||||
return (
|
||||
<div className={"flex w-full min-w-0 flex-col"}>
|
||||
{label && <Label htmlFor={inputId}>{label}</Label>}
|
||||
<div className={cn("relative flex h-[40px] w-full", maxWidthClass)}>
|
||||
<div dir={dir} className={cn("relative flex h-[40px] w-full", maxWidthClass)}>
|
||||
{customPrefix && (
|
||||
<InputAffix
|
||||
content={customPrefix}
|
||||
|
||||
@@ -64,7 +64,7 @@ export function Select<T extends string>({
|
||||
className={"shrink-0 text-nb-gray-200"}
|
||||
/>
|
||||
)}
|
||||
<span className={"flex-1 truncate text-left"}>{current?.label ?? "—"}</span>
|
||||
<span className={"flex-1 truncate text-start"}>{current?.label ?? "—"}</span>
|
||||
<ChevronDown
|
||||
size={12}
|
||||
aria-hidden={"true"}
|
||||
|
||||
Reference in New Issue
Block a user