mirror of
https://github.com/drawdb-io/drawdb.git
synced 2025-05-24 10:29:11 +00:00
Add notes
This commit is contained in:
parent
395ba77a37
commit
6f7dbd9f41
@ -9,12 +9,14 @@ import {
|
||||
} from "../data/data";
|
||||
import Area from "./area";
|
||||
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) {
|
||||
const { tables, setTables, relationships, setRelationships } =
|
||||
useContext(TableContext);
|
||||
const { areas, setAreas } = useContext(AreaContext);
|
||||
const { notes, setNotes } = useContext(NoteContext);
|
||||
const [dragging, setDragging] = useState([ObjectType.NONE, -1]);
|
||||
const [linking, setLinking] = useState(false);
|
||||
const [line, setLine] = useState({
|
||||
@ -68,6 +70,13 @@ export default function Canvas(props) {
|
||||
y: clientY - area.y,
|
||||
});
|
||||
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;
|
||||
setPanOffset({ x: e.clientX, y: e.clientY });
|
||||
|
||||
setTables(
|
||||
tables.map((t) => ({
|
||||
setTables((prev) =>
|
||||
prev.map((t) => ({
|
||||
...t,
|
||||
x: t.x + dx,
|
||||
y: t.y + dy,
|
||||
@ -109,13 +118,9 @@ export default function Canvas(props) {
|
||||
}))
|
||||
);
|
||||
|
||||
setAreas(
|
||||
areas.map((t) => ({
|
||||
...t,
|
||||
x: t.x + dx,
|
||||
y: t.y + dy,
|
||||
}))
|
||||
);
|
||||
setAreas((prev) => prev.map((t) => ({ ...t, x: t.x + dx, y: t.y + dy })));
|
||||
|
||||
setNotes((prev) => prev.map((n) => ({ ...n, x: n.x + dx, y: n.y + dy })));
|
||||
} else if (dragging[0] === ObjectType.TABLE && dragging[1] >= 0) {
|
||||
const updatedTables = tables.map((t) => {
|
||||
if (t.id === dragging[1]) {
|
||||
@ -163,6 +168,22 @@ export default function Canvas(props) {
|
||||
return t;
|
||||
});
|
||||
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) {
|
||||
if (areaResize.dir === "none") return;
|
||||
|
||||
@ -374,14 +395,12 @@ export default function Canvas(props) {
|
||||
key={a.id}
|
||||
areaData={a}
|
||||
onMouseDown={(e) => handleMouseDownRect(e, a.id, ObjectType.AREA)}
|
||||
resize={areaResize}
|
||||
setResize={setAreaResize}
|
||||
initCoords={initCoords}
|
||||
setInitCoords={setInitCoords}
|
||||
setAreas={setAreas}
|
||||
></Area>
|
||||
))}
|
||||
{tables.map((table, i) => (
|
||||
{tables.map((table) => (
|
||||
<Table
|
||||
key={table.id}
|
||||
tableData={table}
|
||||
@ -405,6 +424,13 @@ export default function Canvas(props) {
|
||||
{relationships.map((e, i) => (
|
||||
<Relationship key={i} data={e} />
|
||||
))}
|
||||
{notes.map((n) => (
|
||||
<Note
|
||||
key={n.id}
|
||||
data={n}
|
||||
onMouseDown={(e) => handleMouseDownRect(e, n.id, ObjectType.NOTE)}
|
||||
></Note>
|
||||
))}
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -626,7 +626,7 @@ export default function ControlPanel(props) {
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item
|
||||
icon={
|
||||
layout.shapes ? (
|
||||
layout.notes ? (
|
||||
<IconCheckboxTick />
|
||||
) : (
|
||||
<div className="px-2"></div>
|
||||
@ -635,11 +635,11 @@ export default function ControlPanel(props) {
|
||||
onClick={() =>
|
||||
setLayout((prev) => ({
|
||||
...prev,
|
||||
shapes: !prev.shapes,
|
||||
notes: !prev.notes,
|
||||
}))
|
||||
}
|
||||
>
|
||||
Shapes
|
||||
Notes
|
||||
</Dropdown.Item>
|
||||
</Dropdown.Menu>
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import ReferenceOverview from "./reference_overview";
|
||||
import AreaOverview from "./area_overview";
|
||||
import { Tab } from "../data/data";
|
||||
import { TabContext } from "../pages/editor";
|
||||
import NotesOverview from "./notes_overview";
|
||||
|
||||
const myTheme = createTheme({
|
||||
dark: "light",
|
||||
@ -32,8 +33,8 @@ const EditorPanel = (props) => {
|
||||
{ tab: "Tables", itemKey: Tab.tables },
|
||||
{ tab: "Relationships", itemKey: Tab.relationships },
|
||||
{ tab: "Subject Areas", itemKey: Tab.subject_areas },
|
||||
// { tab: "Shapes", itemKey: Tab.shapes },
|
||||
{ tab: "Editor", itemKey: Tab.editor },
|
||||
{ tab: "Notes", itemKey: Tab.notes },
|
||||
];
|
||||
const contentList = [
|
||||
<TableOverview
|
||||
@ -51,6 +52,7 @@ const EditorPanel = (props) => {
|
||||
props.setCode(e);
|
||||
}}
|
||||
/>,
|
||||
<NotesOverview/>
|
||||
];
|
||||
|
||||
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",
|
||||
relationships: "2",
|
||||
subject_areas: "3",
|
||||
// shapes: "4",
|
||||
editor: "4",
|
||||
notes: "5",
|
||||
};
|
||||
|
||||
const ObjectType = {
|
||||
|
@ -11,12 +11,14 @@ export const LayoutContext = createContext();
|
||||
export const TableContext = createContext();
|
||||
export const AreaContext = createContext();
|
||||
export const TabContext = createContext();
|
||||
export const NoteContext = createContext();
|
||||
|
||||
export default function Editor(props) {
|
||||
const [code, setCode] = useState("");
|
||||
const [tables, setTables] = useState([]);
|
||||
const [relationships, setRelationships] = useState([]);
|
||||
const [areas, setAreas] = useState([]);
|
||||
const [notes, setNotes] = useState([]);
|
||||
const [resize, setResize] = useState(false);
|
||||
const [width, setWidth] = useState(340);
|
||||
const [selectedTable, setSelectedTable] = useState("");
|
||||
@ -30,7 +32,7 @@ export default function Editor(props) {
|
||||
relationships: true,
|
||||
issues: true,
|
||||
editor: true,
|
||||
shapes: true,
|
||||
notes: true,
|
||||
fullscreen: false,
|
||||
});
|
||||
|
||||
@ -50,41 +52,43 @@ export default function Editor(props) {
|
||||
value={{ tables, setTables, relationships, setRelationships }}
|
||||
>
|
||||
<AreaContext.Provider value={{ areas, setAreas }}>
|
||||
<TabContext.Provider value={{ tab, setTab }}>
|
||||
<div className="h-[100vh] overflow-hidden">
|
||||
<ControlPanel />
|
||||
<div
|
||||
className={
|
||||
layout.header
|
||||
? `flex h-[calc(100vh-123.93px)]`
|
||||
: `flex h-[calc(100vh-51.97px)]`
|
||||
}
|
||||
onMouseUp={() => setResize(false)}
|
||||
onMouseMove={dragHandler}
|
||||
>
|
||||
<DndProvider backend={HTML5Backend}>
|
||||
{layout.sidebar && (
|
||||
<EditorPanel
|
||||
<NoteContext.Provider value={{ notes, setNotes }}>
|
||||
<TabContext.Provider value={{ tab, setTab }}>
|
||||
<div className="h-[100vh] overflow-hidden">
|
||||
<ControlPanel />
|
||||
<div
|
||||
className={
|
||||
layout.header
|
||||
? `flex h-[calc(100vh-123.93px)]`
|
||||
: `flex h-[calc(100vh-51.97px)]`
|
||||
}
|
||||
onMouseUp={() => setResize(false)}
|
||||
onMouseMove={dragHandler}
|
||||
>
|
||||
<DndProvider backend={HTML5Backend}>
|
||||
{layout.sidebar && (
|
||||
<EditorPanel
|
||||
code={code}
|
||||
setCode={setCode}
|
||||
resize={resize}
|
||||
setResize={setResize}
|
||||
width={width}
|
||||
selectedTable={selectedTable}
|
||||
setSelectedTable={setSelectedTable}
|
||||
/>
|
||||
)}
|
||||
<Canvas
|
||||
code={code}
|
||||
setCode={setCode}
|
||||
resize={resize}
|
||||
setResize={setResize}
|
||||
width={width}
|
||||
selectedTable={selectedTable}
|
||||
setSelectedTable={setSelectedTable}
|
||||
/>
|
||||
)}
|
||||
<Canvas
|
||||
code={code}
|
||||
setCode={setCode}
|
||||
selectedTable={selectedTable}
|
||||
setSelectedTable={setSelectedTable}
|
||||
/>
|
||||
</DndProvider>
|
||||
{layout.services && <Sidebar />}
|
||||
</DndProvider>
|
||||
{layout.services && <Sidebar />}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</TabContext.Provider>
|
||||
</TabContext.Provider>
|
||||
</NoteContext.Provider>
|
||||
</AreaContext.Provider>
|
||||
</TableContext.Provider>
|
||||
</LayoutContext.Provider>
|
||||
|
Loading…
Reference in New Issue
Block a user