Display UI in RTL languages correctly

This commit is contained in:
tasnim 2024-08-04 15:27:31 +03:00
parent a62a6ba295
commit 5ec54e2445
7 changed files with 60 additions and 14 deletions

View File

@ -18,6 +18,8 @@ import { useLayout, useSettings, useDiagram, useSelect } from "../../hooks";
import TableInfo from "../EditorSidePanel/TablesTab/TableInfo";
import { useTranslation } from "react-i18next";
import { dbToTypes } from "../../data/datatypes";
import { isRtl } from "../../i18n/utils/rtl";
import i18n from "../../i18n/i18n";
export default function Table(props) {
const [hoveredField, setHoveredField] = useState(-1);
@ -84,6 +86,7 @@ export default function Table(props) {
? "border-solid border-blue-500"
: "border-zinc-500"
}`}
style={{ direction: "ltr" }}
>
<div
className="h-[10px] w-full rounded-t-md"
@ -190,7 +193,10 @@ export default function Table(props) {
key={i}
content={
<div className="popover-theme">
<div className="flex justify-between items-center pb-2">
<div
className="flex justify-between items-center pb-2"
style={{ direction: "ltr" }}
>
<p className="me-4 font-bold">{e.name}</p>
<p className="ms-4">
{e.type +
@ -235,6 +241,11 @@ export default function Table(props) {
}
position="right"
showArrow
style={
isRtl(i18n.language)
? { direction: "rtl" }
: { direction: "ltr" }
}
>
{field(e, i)}
</Popover>

View File

@ -2,6 +2,7 @@ import { useState } from "react";
import {
IconCaretdown,
IconChevronRight,
IconChevronLeft,
IconChevronUp,
IconChevronDown,
IconSaveStroked,
@ -68,6 +69,7 @@ import { useTranslation } from "react-i18next";
import { exportSQL } from "../../utils/exportSQL";
import { databases } from "../../data/databases";
import { jsonToMermaid } from "../../utils/exportAs/mermaid";
import { isRtl } from "../../i18n/utils/rtl";
export default function ControlPanel({
diagramId,
@ -109,7 +111,7 @@ export default function ControlPanel({
const { undoStack, redoStack, setUndoStack, setRedoStack } = useUndoRedo();
const { selectedElement, setSelectedElement } = useSelect();
const { transform, setTransform } = useTransform();
const { t } = useTranslation();
const { t, i18n } = useTranslation();
const navigate = useNavigate();
const invertLayout = (component) =>
@ -1374,7 +1376,10 @@ export default function ControlPanel({
function toolbar() {
return (
<div className="py-1.5 px-5 flex justify-between items-center rounded-xl my-1 sm:mx-1 xl:mx-6 select-none overflow-hidden toolbar-theme">
<div
className="py-1.5 px-5 flex justify-between items-center rounded-xl my-1 sm:mx-1 xl:mx-6 select-none overflow-hidden toolbar-theme"
style={isRtl(i18n.language) ? { direction: "rtl" } : {}}
>
<div className="flex justify-start items-center">
<LayoutDropdown />
<Divider layout="vertical" margin="8px" />
@ -1382,7 +1387,9 @@ export default function ControlPanel({
style={{ width: "240px" }}
position="bottomLeft"
render={
<Dropdown.Menu>
<Dropdown.Menu
style={isRtl(i18n.language) ? { direction: "rtl" } : {}}
>
<Dropdown.Item
onClick={fitWindow}
style={{ display: "flex", justifyContent: "space-between" }}
@ -1562,7 +1569,10 @@ export default function ControlPanel({
function header() {
return (
<nav className="flex justify-between pt-1 items-center whitespace-nowrap">
<nav
className="flex justify-between pt-1 items-center whitespace-nowrap"
style={isRtl(i18n.language) ? { direction: "rtl" } : {}}
>
<div className="flex justify-start items-center">
<Link to="/">
<img
@ -1608,7 +1618,10 @@ export default function ControlPanel({
<Dropdown
key={category}
position="bottomLeft"
style={{ width: "240px" }}
style={{
width: "240px",
direction: isRtl(i18n.language) ? "rtl" : "ltr",
}}
render={
<Dropdown.Menu>
{Object.keys(menu[category]).map((item, index) => {
@ -1642,7 +1655,12 @@ export default function ControlPanel({
onClick={menu[category][item].function}
>
{t(item)}
{isRtl(i18n.language) ? (
<IconChevronLeft />
) : (
<IconChevronRight />
)}
</Dropdown.Item>
</Dropdown>
);

View File

@ -7,6 +7,8 @@ import { Dropdown } from "@douyinfe/semi-ui";
import { useFullscreen, useLayout } from "../../hooks";
import { enterFullscreen, exitFullscreen } from "../../utils/fullscreen";
import { useTranslation } from "react-i18next";
import { isRtl } from "../../i18n/utils/rtl";
import i18n from "../../i18n/i18n";
export default function LayoutDropdown() {
const fullscreen = useFullscreen();
@ -19,7 +21,10 @@ export default function LayoutDropdown() {
return (
<Dropdown
position="bottomLeft"
style={{ width: "180px" }}
style={{
width: "180px",
direction: isRtl(i18n.language) ? "rtl" : "ltr",
}}
render={
<Dropdown.Menu>
<Dropdown.Item
@ -48,9 +53,7 @@ export default function LayoutDropdown() {
</Dropdown.Item>
<Dropdown.Divider />
<Dropdown.Item
icon={
fullscreen ? <IconCheckboxTick /> : <div className="px-2" />
}
icon={fullscreen ? <IconCheckboxTick /> : <div className="px-2" />}
onClick={() => {
if (fullscreen) {
exitFullscreen();

View File

@ -37,6 +37,7 @@ import { githubLight } from "@uiw/codemirror-theme-github";
import { useTranslation } from "react-i18next";
import { importSQL } from "../../../utils/importSQL";
import { databases } from "../../../data/databases";
import { isRtl } from "../../../i18n/utils/rtl";
const languageExtension = {
sql: [sql()],
@ -53,7 +54,7 @@ export default function Modal({
setExportData,
importDb,
}) {
const { t } = useTranslation();
const { t, i18n } = useTranslation();
const { setTables, setRelationships, database, setDatabase } = useDiagram();
const { setNotes } = useNotes();
const { setAreas } = useAreas();
@ -324,6 +325,7 @@ export default function Modal({
return (
<SemiUIModal
style={isRtl(i18n.language) ? { direction: "rtl" } : {}}
title={getModalTitle(modal)}
visible={modal !== MODAL.NONE}
onOk={getModalOnOk}
@ -362,7 +364,11 @@ export default function Modal({
}}
cancelText={t("cancel")}
width={modal === MODAL.NEW || modal === MODAL.OPEN ? 740 : 600}
bodyStyle={{ maxHeight: window.innerHeight - 280, overflow: "auto" }}
bodyStyle={{
maxHeight: window.innerHeight - 280,
overflow: "auto",
direction: "ltr",
}}
>
{getModalBody()}
</SemiUIModal>

View File

@ -11,6 +11,8 @@ import { useTranslation } from "react-i18next";
import { useMemo } from "react";
import { databases } from "../../data/databases";
import EnumsTab from "./EnumsTab/EnumsTab";
import { isRtl } from "../../i18n/utils/rtl";
import i18n from "../../i18n/i18n";
export default function SidePanel({ width, resize, setResize }) {
const { layout } = useLayout();
@ -46,7 +48,7 @@ export default function SidePanel({ width, resize, setResize }) {
});
}
return tabs;
return isRtl(i18n.language) ? tabs.reverse() : tabs;
}, [t, database]);
return (
@ -64,6 +66,7 @@ export default function SidePanel({ width, resize, setResize }) {
setSelectedElement((prev) => ({ ...prev, currentTab: key }))
}
collapsible
tabBarStyle={{ direction: "ltr" }}
>
{tabList.length &&
tabList.map((tab) => (

View File

@ -22,6 +22,8 @@ import FloatingControls from "./FloatingControls";
import { Modal } from "@douyinfe/semi-ui";
import { useTranslation } from "react-i18next";
import { databases } from "../data/databases";
import { isRtl } from "../i18n/utils/rtl";
import i18n from "../i18n/i18n";
export default function WorkSpace() {
const [id, setId] = useState(0);
@ -358,6 +360,7 @@ export default function WorkSpace() {
// https://stackoverflow.com/a/70976017/1137077
e.target.releasePointerCapture(e.pointerId);
}}
style={isRtl(i18n.language) ? { direction: "rtl" } : {}}
>
{layout.sidebar && (
<SidePanel resize={resize} setResize={setResize} width={width} />

2
src/i18n/utils/rtl.js Normal file
View File

@ -0,0 +1,2 @@
const rtlLanguages = ["ar", "he", "fa", "ps", "ur"];
export const isRtl = (language) => rtlLanguages.includes(language);