mirror of
https://github.com/drawdb-io/drawdb.git
synced 2025-05-24 18:39:12 +00:00
Add notes
This commit is contained in:
parent
395ba77a37
commit
6f7dbd9f41
@ -9,12 +9,14 @@ import {
|
|||||||
} from "../data/data";
|
} from "../data/data";
|
||||||
import Area from "./area";
|
import Area from "./area";
|
||||||
import Relationship from "./relationship";
|
import Relationship from "./relationship";
|
||||||
import { AreaContext, TableContext } from "../pages/editor";
|
import { AreaContext, NoteContext, TableContext } from "../pages/editor";
|
||||||
|
import Note from "./note";
|
||||||
|
|
||||||
export default function Canvas(props) {
|
export default function Canvas(props) {
|
||||||
const { tables, setTables, relationships, setRelationships } =
|
const { tables, setTables, relationships, setRelationships } =
|
||||||
useContext(TableContext);
|
useContext(TableContext);
|
||||||
const { areas, setAreas } = useContext(AreaContext);
|
const { areas, setAreas } = useContext(AreaContext);
|
||||||
|
const { notes, setNotes } = useContext(NoteContext);
|
||||||
const [dragging, setDragging] = useState([ObjectType.NONE, -1]);
|
const [dragging, setDragging] = useState([ObjectType.NONE, -1]);
|
||||||
const [linking, setLinking] = useState(false);
|
const [linking, setLinking] = useState(false);
|
||||||
const [line, setLine] = useState({
|
const [line, setLine] = useState({
|
||||||
@ -68,6 +70,13 @@ export default function Canvas(props) {
|
|||||||
y: clientY - area.y,
|
y: clientY - area.y,
|
||||||
});
|
});
|
||||||
setDragging([ObjectType.AREA, id]);
|
setDragging([ObjectType.AREA, id]);
|
||||||
|
} else if (type === ObjectType.NOTE) {
|
||||||
|
const note = notes.find((t) => t.id === id);
|
||||||
|
setOffset({
|
||||||
|
x: clientX - note.x,
|
||||||
|
y: clientY - note.y,
|
||||||
|
});
|
||||||
|
setDragging([ObjectType.NOTE, id]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -91,8 +100,8 @@ export default function Canvas(props) {
|
|||||||
const dy = e.clientY - panOffset.y;
|
const dy = e.clientY - panOffset.y;
|
||||||
setPanOffset({ x: e.clientX, y: e.clientY });
|
setPanOffset({ x: e.clientX, y: e.clientY });
|
||||||
|
|
||||||
setTables(
|
setTables((prev) =>
|
||||||
tables.map((t) => ({
|
prev.map((t) => ({
|
||||||
...t,
|
...t,
|
||||||
x: t.x + dx,
|
x: t.x + dx,
|
||||||
y: t.y + dy,
|
y: t.y + dy,
|
||||||
@ -109,13 +118,9 @@ export default function Canvas(props) {
|
|||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|
||||||
setAreas(
|
setAreas((prev) => prev.map((t) => ({ ...t, x: t.x + dx, y: t.y + dy })));
|
||||||
areas.map((t) => ({
|
|
||||||
...t,
|
setNotes((prev) => prev.map((n) => ({ ...n, x: n.x + dx, y: n.y + dy })));
|
||||||
x: t.x + dx,
|
|
||||||
y: t.y + dy,
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
} else if (dragging[0] === ObjectType.TABLE && dragging[1] >= 0) {
|
} else if (dragging[0] === ObjectType.TABLE && dragging[1] >= 0) {
|
||||||
const updatedTables = tables.map((t) => {
|
const updatedTables = tables.map((t) => {
|
||||||
if (t.id === dragging[1]) {
|
if (t.id === dragging[1]) {
|
||||||
@ -163,6 +168,22 @@ export default function Canvas(props) {
|
|||||||
return t;
|
return t;
|
||||||
});
|
});
|
||||||
setAreas(updatedAreas);
|
setAreas(updatedAreas);
|
||||||
|
} else if (
|
||||||
|
dragging[0] === ObjectType.NOTE &&
|
||||||
|
dragging[1] >= 0
|
||||||
|
) {
|
||||||
|
setNotes((prev) =>
|
||||||
|
prev.map((t) => {
|
||||||
|
if (t.id === dragging[1]) {
|
||||||
|
return {
|
||||||
|
...t,
|
||||||
|
x: e.clientX - offset.x,
|
||||||
|
y: e.clientY - offset.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
})
|
||||||
|
);
|
||||||
} else if (areaResize.id !== -1) {
|
} else if (areaResize.id !== -1) {
|
||||||
if (areaResize.dir === "none") return;
|
if (areaResize.dir === "none") return;
|
||||||
|
|
||||||
@ -374,14 +395,12 @@ export default function Canvas(props) {
|
|||||||
key={a.id}
|
key={a.id}
|
||||||
areaData={a}
|
areaData={a}
|
||||||
onMouseDown={(e) => handleMouseDownRect(e, a.id, ObjectType.AREA)}
|
onMouseDown={(e) => handleMouseDownRect(e, a.id, ObjectType.AREA)}
|
||||||
resize={areaResize}
|
|
||||||
setResize={setAreaResize}
|
setResize={setAreaResize}
|
||||||
initCoords={initCoords}
|
initCoords={initCoords}
|
||||||
setInitCoords={setInitCoords}
|
setInitCoords={setInitCoords}
|
||||||
setAreas={setAreas}
|
|
||||||
></Area>
|
></Area>
|
||||||
))}
|
))}
|
||||||
{tables.map((table, i) => (
|
{tables.map((table) => (
|
||||||
<Table
|
<Table
|
||||||
key={table.id}
|
key={table.id}
|
||||||
tableData={table}
|
tableData={table}
|
||||||
@ -405,6 +424,13 @@ export default function Canvas(props) {
|
|||||||
{relationships.map((e, i) => (
|
{relationships.map((e, i) => (
|
||||||
<Relationship key={i} data={e} />
|
<Relationship key={i} data={e} />
|
||||||
))}
|
))}
|
||||||
|
{notes.map((n) => (
|
||||||
|
<Note
|
||||||
|
key={n.id}
|
||||||
|
data={n}
|
||||||
|
onMouseDown={(e) => handleMouseDownRect(e, n.id, ObjectType.NOTE)}
|
||||||
|
></Note>
|
||||||
|
))}
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -626,7 +626,7 @@ export default function ControlPanel(props) {
|
|||||||
</Dropdown.Item>
|
</Dropdown.Item>
|
||||||
<Dropdown.Item
|
<Dropdown.Item
|
||||||
icon={
|
icon={
|
||||||
layout.shapes ? (
|
layout.notes ? (
|
||||||
<IconCheckboxTick />
|
<IconCheckboxTick />
|
||||||
) : (
|
) : (
|
||||||
<div className="px-2"></div>
|
<div className="px-2"></div>
|
||||||
@ -635,11 +635,11 @@ export default function ControlPanel(props) {
|
|||||||
onClick={() =>
|
onClick={() =>
|
||||||
setLayout((prev) => ({
|
setLayout((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
shapes: !prev.shapes,
|
notes: !prev.notes,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Shapes
|
Notes
|
||||||
</Dropdown.Item>
|
</Dropdown.Item>
|
||||||
</Dropdown.Menu>
|
</Dropdown.Menu>
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import ReferenceOverview from "./reference_overview";
|
|||||||
import AreaOverview from "./area_overview";
|
import AreaOverview from "./area_overview";
|
||||||
import { Tab } from "../data/data";
|
import { Tab } from "../data/data";
|
||||||
import { TabContext } from "../pages/editor";
|
import { TabContext } from "../pages/editor";
|
||||||
|
import NotesOverview from "./notes_overview";
|
||||||
|
|
||||||
const myTheme = createTheme({
|
const myTheme = createTheme({
|
||||||
dark: "light",
|
dark: "light",
|
||||||
@ -32,8 +33,8 @@ const EditorPanel = (props) => {
|
|||||||
{ tab: "Tables", itemKey: Tab.tables },
|
{ tab: "Tables", itemKey: Tab.tables },
|
||||||
{ tab: "Relationships", itemKey: Tab.relationships },
|
{ tab: "Relationships", itemKey: Tab.relationships },
|
||||||
{ tab: "Subject Areas", itemKey: Tab.subject_areas },
|
{ tab: "Subject Areas", itemKey: Tab.subject_areas },
|
||||||
// { tab: "Shapes", itemKey: Tab.shapes },
|
|
||||||
{ tab: "Editor", itemKey: Tab.editor },
|
{ tab: "Editor", itemKey: Tab.editor },
|
||||||
|
{ tab: "Notes", itemKey: Tab.notes },
|
||||||
];
|
];
|
||||||
const contentList = [
|
const contentList = [
|
||||||
<TableOverview
|
<TableOverview
|
||||||
@ -51,6 +52,7 @@ const EditorPanel = (props) => {
|
|||||||
props.setCode(e);
|
props.setCode(e);
|
||||||
}}
|
}}
|
||||||
/>,
|
/>,
|
||||||
|
<NotesOverview/>
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
78
src/components/note.jsx
Normal file
78
src/components/note.jsx
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import React, { useContext, useState } from "react";
|
||||||
|
import { NoteContext } from "../pages/editor";
|
||||||
|
|
||||||
|
export default function Note(props) {
|
||||||
|
const { setNotes } = useContext(NoteContext);
|
||||||
|
const [size, setSize] = useState({ w: 180, h: 88 });
|
||||||
|
const r = 3;
|
||||||
|
const fold = 24;
|
||||||
|
|
||||||
|
const handleChange = (e) => {
|
||||||
|
const textarea = document.getElementById(`note_${props.data.id}`);
|
||||||
|
const newHeight = textarea.scrollHeight + 16 + 20 + 4;
|
||||||
|
setSize((prevSize) => ({ ...prevSize, h: newHeight }));
|
||||||
|
textarea.style.height = "0";
|
||||||
|
textarea.style.height = textarea.scrollHeight + "px";
|
||||||
|
|
||||||
|
setNotes((prev) =>
|
||||||
|
prev.map((n) => {
|
||||||
|
if (n.id === props.data.id) {
|
||||||
|
return { ...n, content: e.target.value };
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<g>
|
||||||
|
<path
|
||||||
|
d={`M${props.data.x + fold} ${props.data.y} L${
|
||||||
|
props.data.x + size.w - r
|
||||||
|
} ${props.data.y} A${r} ${r} 0 0 1 ${props.data.x + size.w} ${
|
||||||
|
props.data.y + r
|
||||||
|
} L${props.data.x + size.w} ${
|
||||||
|
props.data.y + size.h - r
|
||||||
|
} A${r} ${r} 0 0 1 ${props.data.x + size.w - r} ${
|
||||||
|
props.data.y + size.h
|
||||||
|
} L${props.data.x + r} ${props.data.y + size.h} A${r} ${r} 0 0 1 ${
|
||||||
|
props.data.x
|
||||||
|
} ${props.data.y + size.h - r} L${props.data.x} ${props.data.y + fold}`}
|
||||||
|
fill="#fcf7ac"
|
||||||
|
stroke="#665b25"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth="0.6"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d={`M${props.data.x} ${props.data.y + fold} L${
|
||||||
|
props.data.x + fold - r
|
||||||
|
} ${props.data.y + fold} A${r} ${r} 0 0 0 ${props.data.x + fold} ${
|
||||||
|
props.data.y + fold - r
|
||||||
|
} L${props.data.x + fold} ${props.data.y} L${props.data.x} ${
|
||||||
|
props.data.y + fold
|
||||||
|
} Z`}
|
||||||
|
fill="#fcf7ac"
|
||||||
|
stroke="#665b25"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth="0.6"
|
||||||
|
/>
|
||||||
|
<foreignObject
|
||||||
|
x={props.data.x}
|
||||||
|
y={props.data.y}
|
||||||
|
width={size.w}
|
||||||
|
height={size.h}
|
||||||
|
onMouseDown={props.onMouseDown}
|
||||||
|
>
|
||||||
|
<div className="text-gray-900 select-none w-full h-full cursor-move px-3 py-2">
|
||||||
|
<label htmlFor={`note_${props.data.id}`} className="ms-5">{props.data.title}</label>
|
||||||
|
<textarea
|
||||||
|
id={`note_${props.data.id}`}
|
||||||
|
value={props.data.content}
|
||||||
|
onInput={handleChange}
|
||||||
|
className="mt-1 w-full resize-none outline-none overflow-y-hidden border-none select-none bg-[#fcf7ac]"
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
</foreignObject>
|
||||||
|
</g>
|
||||||
|
);
|
||||||
|
}
|
65
src/components/notes_overview.jsx
Normal file
65
src/components/notes_overview.jsx
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import React, { useContext } from "react";
|
||||||
|
import {
|
||||||
|
Empty,
|
||||||
|
Row,
|
||||||
|
Col,
|
||||||
|
Button,
|
||||||
|
// Input,
|
||||||
|
// Popover,
|
||||||
|
// Toast,
|
||||||
|
} from "@douyinfe/semi-ui";
|
||||||
|
import {
|
||||||
|
IllustrationNoContent,
|
||||||
|
IllustrationNoContentDark,
|
||||||
|
} from "@douyinfe/semi-illustrations";
|
||||||
|
import { IconPlus } from "@douyinfe/semi-icons";
|
||||||
|
import { NoteContext } from "../pages/editor";
|
||||||
|
|
||||||
|
export default function NotesOverview(props) {
|
||||||
|
const { notes, setNotes } = useContext(NoteContext);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Row gutter={6}>
|
||||||
|
<Col span={24}>
|
||||||
|
<Button
|
||||||
|
icon={<IconPlus />}
|
||||||
|
block
|
||||||
|
onClick={() => {
|
||||||
|
const newNote = {
|
||||||
|
id: notes.length,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
title: `note_${notes.length}`,
|
||||||
|
content: ""
|
||||||
|
};
|
||||||
|
setNotes((prev) => [...prev, newNote]);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Add note
|
||||||
|
</Button>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
{notes.length <= 0 ? (
|
||||||
|
<div className="select-none mt-2">
|
||||||
|
<Empty
|
||||||
|
image={
|
||||||
|
<IllustrationNoContent style={{ width: 160, height: 160 }} />
|
||||||
|
}
|
||||||
|
darkModeImage={
|
||||||
|
<IllustrationNoContentDark style={{ width: 160, height: 160 }} />
|
||||||
|
}
|
||||||
|
title="No text notes"
|
||||||
|
description="Add notes cuz why not!"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="p-2">
|
||||||
|
{notes.map((n, i) => (
|
||||||
|
<div key={n.id}>{n.title}</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -61,8 +61,8 @@ const Tab = {
|
|||||||
tables: "1",
|
tables: "1",
|
||||||
relationships: "2",
|
relationships: "2",
|
||||||
subject_areas: "3",
|
subject_areas: "3",
|
||||||
// shapes: "4",
|
|
||||||
editor: "4",
|
editor: "4",
|
||||||
|
notes: "5",
|
||||||
};
|
};
|
||||||
|
|
||||||
const ObjectType = {
|
const ObjectType = {
|
||||||
|
@ -11,12 +11,14 @@ export const LayoutContext = createContext();
|
|||||||
export const TableContext = createContext();
|
export const TableContext = createContext();
|
||||||
export const AreaContext = createContext();
|
export const AreaContext = createContext();
|
||||||
export const TabContext = createContext();
|
export const TabContext = createContext();
|
||||||
|
export const NoteContext = createContext();
|
||||||
|
|
||||||
export default function Editor(props) {
|
export default function Editor(props) {
|
||||||
const [code, setCode] = useState("");
|
const [code, setCode] = useState("");
|
||||||
const [tables, setTables] = useState([]);
|
const [tables, setTables] = useState([]);
|
||||||
const [relationships, setRelationships] = useState([]);
|
const [relationships, setRelationships] = useState([]);
|
||||||
const [areas, setAreas] = useState([]);
|
const [areas, setAreas] = useState([]);
|
||||||
|
const [notes, setNotes] = useState([]);
|
||||||
const [resize, setResize] = useState(false);
|
const [resize, setResize] = useState(false);
|
||||||
const [width, setWidth] = useState(340);
|
const [width, setWidth] = useState(340);
|
||||||
const [selectedTable, setSelectedTable] = useState("");
|
const [selectedTable, setSelectedTable] = useState("");
|
||||||
@ -30,7 +32,7 @@ export default function Editor(props) {
|
|||||||
relationships: true,
|
relationships: true,
|
||||||
issues: true,
|
issues: true,
|
||||||
editor: true,
|
editor: true,
|
||||||
shapes: true,
|
notes: true,
|
||||||
fullscreen: false,
|
fullscreen: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -50,6 +52,7 @@ export default function Editor(props) {
|
|||||||
value={{ tables, setTables, relationships, setRelationships }}
|
value={{ tables, setTables, relationships, setRelationships }}
|
||||||
>
|
>
|
||||||
<AreaContext.Provider value={{ areas, setAreas }}>
|
<AreaContext.Provider value={{ areas, setAreas }}>
|
||||||
|
<NoteContext.Provider value={{ notes, setNotes }}>
|
||||||
<TabContext.Provider value={{ tab, setTab }}>
|
<TabContext.Provider value={{ tab, setTab }}>
|
||||||
<div className="h-[100vh] overflow-hidden">
|
<div className="h-[100vh] overflow-hidden">
|
||||||
<ControlPanel />
|
<ControlPanel />
|
||||||
@ -85,6 +88,7 @@ export default function Editor(props) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</TabContext.Provider>
|
</TabContext.Provider>
|
||||||
|
</NoteContext.Provider>
|
||||||
</AreaContext.Provider>
|
</AreaContext.Provider>
|
||||||
</TableContext.Provider>
|
</TableContext.Provider>
|
||||||
</LayoutContext.Provider>
|
</LayoutContext.Provider>
|
||||||
|
Loading…
Reference in New Issue
Block a user