diff --git a/src/components/EditorCanvas/Canvas.jsx b/src/components/EditorCanvas/Canvas.jsx index e0c1695e5..035fc2eda 100644 --- a/src/components/EditorCanvas/Canvas.jsx +++ b/src/components/EditorCanvas/Canvas.jsx @@ -1,4 +1,4 @@ -import { useRef, useState, useEffect } from "react"; +import { useRef, useState, useEffect, useCallback } from "react"; import { Action, RelationshipType, @@ -15,6 +15,7 @@ import { } from "../../data/constants"; import { dbToTypes } from "../../data/datatypes"; import { Toast, Modal, Input, InputNumber } from "@douyinfe/semi-ui"; +import ColorPicker from "../ColorPicker"; import Table from "./Table"; import Area from "./Area"; import Relationship from "./Relationship"; @@ -269,6 +270,14 @@ export default function Canvas() { field: null, }); + const [fieldForeignKeyColorModal, setFieldForeignKeyColorModal] = useState({ + visible: false, + tableId: null, + fieldId: null, + field: null, + currentColor: "", + }); + // Field properties modal internal state const [fieldPropertiesPrecision, setFieldPropertiesPrecision] = useState(""); const [fieldPropertiesAccuracy, setFieldPropertiesAccuracy] = useState(""); @@ -1073,7 +1082,8 @@ export default function Canvas() { if (!match) { return { valid: false, - message: "Invalid format. Use (x,y) where x is 0 or 1, and y is greater than 1 or *", + message: + "Invalid format. Use (x,y) where x is 0 or 1, and y is greater than 1 or *", }; } @@ -1817,6 +1827,99 @@ export default function Canvas() { setFieldPropertiesAccuracy(""); }; + const handleSetFieldForeignKeyColor = () => { + if ( + fieldContextMenu.tableId !== null && + fieldContextMenu.fieldId !== null + ) { + const table = tables.find((t) => t.id === fieldContextMenu.tableId); + const field = table?.fields.find( + (f) => f.id === fieldContextMenu.fieldId, + ); + + setFieldForeignKeyColorModal({ + visible: true, + tableId: fieldContextMenu.tableId, + fieldId: fieldContextMenu.fieldId, + field: field, + currentColor: field?.fkColor || settings.defaultFkColor, + }); + handleFieldContextMenuClose(); + } + }; + + const handleFieldForeignKeyColorConfirm = useCallback( + (color) => { + const { tableId, fieldId } = fieldForeignKeyColorModal; + + pushUndo({ + action: Action.EDIT, + element: ObjectType.TABLE, + component: "field", + tid: tableId, + fid: fieldId, + undo: { + fkColor: + tables + .find((t) => t.id === tableId) + ?.fields.find((f) => f.id === fieldId)?.fkColor || null, + }, + redo: { fkColor: color }, + message: t("edit_table", { + tableName: tables.find((t) => t.id === tableId)?.name || "", + extra: "[foreign key color]", + }), + }); + + updateField(tableId, fieldId, { fkColor: color }); + setFieldForeignKeyColorModal({ + visible: false, + tableId: null, + fieldId: null, + field: null, + currentColor: "", + }); + }, + [fieldForeignKeyColorModal, pushUndo, tables, t, updateField], + ); + + const handleFieldForeignKeyColorCancel = useCallback(() => { + setFieldForeignKeyColorModal({ + visible: false, + tableId: null, + fieldId: null, + field: null, + currentColor: "", + }); + }, []); + + // Handle keyboard events for FK color modal + useEffect(() => { + if (!fieldForeignKeyColorModal.visible) return; + + const handleKeyDown = (e) => { + if (e.key === "Enter") { + e.preventDefault(); + handleFieldForeignKeyColorConfirm( + fieldForeignKeyColorModal.currentColor, + ); + } else if (e.key === "Escape") { + e.preventDefault(); + handleFieldForeignKeyColorCancel(); + } + }; + + document.addEventListener("keydown", handleKeyDown); + return () => { + document.removeEventListener("keydown", handleKeyDown); + }; + }, [ + fieldForeignKeyColorModal.visible, + fieldForeignKeyColorModal.currentColor, + handleFieldForeignKeyColorConfirm, + handleFieldForeignKeyColorCancel, + ]); + const handleEditNoteContent = () => { if (noteContextMenu.noteId !== null) { // Focus on the textarea for the note @@ -3411,6 +3514,7 @@ export default function Canvas() { onToggleUnique={handleToggleFieldUnique} onToggleAutoIncrement={handleToggleFieldAutoIncrement} onEditProperties={handleFieldEditProperties} + onSetForeignKeyColor={handleSetFieldForeignKeyColor} /> + + + handleFieldForeignKeyColorConfirm( + fieldForeignKeyColorModal.currentColor, + ) + } + onCancel={handleFieldForeignKeyColorCancel} + okText={t("confirm")} + cancelText={t("cancel")} + maskClosable={false} + keyboard={true} + > +
+
Select color:
+ { + setFieldForeignKeyColorModal((prev) => ({ + ...prev, + currentColor: settings.defaultFkColor, + })); + }} + onPickColor={(color) => { + setFieldForeignKeyColorModal((prev) => ({ + ...prev, + currentColor: color, + })); + }} + /> +
+
); } diff --git a/src/components/EditorCanvas/FieldContextMenu.jsx b/src/components/EditorCanvas/FieldContextMenu.jsx index ac179f2f8..799d0e2ef 100644 --- a/src/components/EditorCanvas/FieldContextMenu.jsx +++ b/src/components/EditorCanvas/FieldContextMenu.jsx @@ -6,6 +6,7 @@ import { IconEdit2Stroked, IconCheckboxTick, IconMinus, + IconColorPalette, } from "@douyinfe/semi-icons"; import { useTranslation } from "react-i18next"; import { useSettings } from "../../hooks"; @@ -25,6 +26,7 @@ export default function FieldContextMenu({ onToggleUnique, onToggleAutoIncrement, onEditProperties, + onSetForeignKeyColor, }) { const { t } = useTranslation(); const { settings } = useSettings(); @@ -121,6 +123,15 @@ export default function FieldContextMenu({ onClose(); }, }, + // Only show FK color option for foreign key fields + ...(field?.foreignK ? [{ + label: `Set ${t("foreign_key")} Color`, + icon: , + onClick: () => { + onSetForeignKeyColor(); + onClose(); + }, + }] : []), { type: "divider", }, diff --git a/src/components/EditorCanvas/Table.jsx b/src/components/EditorCanvas/Table.jsx index e084dc9ff..f7082ae9a 100644 --- a/src/components/EditorCanvas/Table.jsx +++ b/src/components/EditorCanvas/Table.jsx @@ -380,7 +380,7 @@ export default function Table(props) {

{e.name} @@ -610,7 +610,7 @@ export default function Table(props) { fieldData.foreignK ? "font-medium" : "" }`} style={{ - color: fieldData.foreignK ? settings.defaultFkColor : 'inherit' + color: fieldData.foreignK ? (fieldData.fkColor || settings.defaultFkColor) : 'inherit' }} > {fieldData.name} diff --git a/src/components/EditorSidePanel/TablesTab/FieldDetails.jsx b/src/components/EditorSidePanel/TablesTab/FieldDetails.jsx index f013555d8..6718f2a5c 100644 --- a/src/components/EditorSidePanel/TablesTab/FieldDetails.jsx +++ b/src/components/EditorSidePanel/TablesTab/FieldDetails.jsx @@ -6,13 +6,15 @@ import { TagInput, Checkbox, Toast, + Popover, } from "@douyinfe/semi-ui"; import { Action, ObjectType } from "../../../data/constants"; import { IconDeleteStroked } from "@douyinfe/semi-icons"; -import { useDiagram, useUndoRedo } from "../../../hooks"; +import { useDiagram, useUndoRedo, useSettings } from "../../../hooks"; import { useTranslation } from "react-i18next"; import { dbToTypes } from "../../../data/datatypes"; import { databases } from "../../../data/databases"; +import ColorPicker from "../../ColorPicker"; export default function FieldDetails({ data, tid, index }) { const { t } = useTranslation(); @@ -20,6 +22,7 @@ export default function FieldDetails({ data, tid, index }) { const { pushUndo } = useUndoRedo(); const { updateField, deleteField } = useDiagram(); const [editField, setEditField] = useState({}); + const { settings } = useSettings(); return (

@@ -243,6 +246,62 @@ export default function FieldDetails({ data, tid, index }) { />
)} + {data.foreignK && ( +
+
{t("foreign_key")} Color
+ + { + pushUndo({ + action: Action.EDIT, + element: ObjectType.TABLE, + component: "field", + tid: tid, + fid: index, + undo: { fkColor: data.fkColor }, + redo: { fkColor: undefined }, + message: t("edit_table", { + tableName: tables[tid].name, + extra: "[field color]", + }), + }); + updateField(tid, index, { fkColor: undefined }); + }} + onPickColor={(color) => { + pushUndo({ + action: Action.EDIT, + element: ObjectType.TABLE, + component: "field", + tid: tid, + fid: index, + undo: { fkColor: data.fkColor }, + redo: { fkColor: color }, + message: t("edit_table", { + tableName: tables[tid].name, + extra: "[field color]", + }), + }); + updateField(tid, index, { fkColor: color }); + }} + /> +
+ } + trigger="click" + position="bottomLeft" + showArrow + > +
+ +
+ )}
{t("comment")}