This commit is contained in:
1ilit 2023-09-19 15:48:20 +03:00
parent 003c2f734c
commit 33c5118c83
9 changed files with 154 additions and 86 deletions

2
.gitignore vendored
View File

@ -21,3 +21,5 @@
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
test.html

BIN
src/assets/icon_136.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

BIN
src/assets/icon_64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
src/assets/icon_dark_64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -1,27 +1,31 @@
import { React, useState } from "react"; import { React, useState } from "react";
import {menu} from "../data/data"; import { menu } from "../data/data";
import { import {
IconCaretUp, IconCaretdown,
IconCaretDown, IconChevronRight,
IconRight, IconShareStroked,
} from "@arco-design/web-react/icon"; IconChevronUp,
import "@arco-design/web-react/dist/css/arco.css"; IconChevronDown,
IconPlus,
} from "@douyinfe/semi-icons";
import { Link } from "react-router-dom";
import icon from "../assets/icon_dark_64.png";
import {
Avatar,
AvatarGroup,
Button,
Divider,
Dropdown,
} from "@douyinfe/semi-ui";
export default function ControlPanel() { export default function ControlPanel() {
let cursor = 0;
const iota = (restart = false) => {
const temp = cursor;
cursor++;
return temp;
};
const Tool = { const Tool = {
TOOLBAR: iota(), TOOLBAR: 0,
ZOOM: iota(), ZOOM: 1,
UNDO: iota(), UNDO: 2,
REDO: iota(), REDO: 3,
ADD: iota(), ADD: 4,
COUNT: iota(), COUNT: 5,
}; };
const [showToolBar, setShowToolBar] = useState(true); const [showToolBar, setShowToolBar] = useState(true);
@ -47,64 +51,119 @@ export default function ControlPanel() {
}; };
return ( return (
<nav className="bg-gray-200 relative"> <>
<div className="flex justify-between items-center">
<ul className="flex justify-start text-md ms-3 select-none relative">
{Object.keys(menu).map((category) => (
<div key={category}>
<div className="peer px-3 py-1 bg-gray-200 hover:bg-gray-300 relative z-50">
{category}
</div>
<ul className="hidden peer-hover:flex hover:flex w-[200px] flex-col bg-white drop-shadow-lg absolute z-50">
{Object.keys(menu[category]).map((item, index) => {
if (menu[category][item].length > 0) {
return (
<div
key={index}
className="group relative px-5 py-3 hover:bg-gray-200 z-50"
>
<div className="flex justify-between items-center">
<li>{item}</li>
<IconRight />
</div>
<ul className="hidden group-hover:flex hover:flex w-[200px] flex-col bg-white drop-shadow-lg absolute z-50 top-0 left-full">
{menu[category][item].map((e) => (
<li
key={e}
className="px-5 py-3 hover:bg-gray-200 z-50"
>
{e}
</li>
))}
</ul>
</div>
);
}
return (
<li
className="px-5 py-3 hover:bg-gray-200 relative z-50"
key={index}
>
{item}
</li>
);
})}
</ul>
</div>
))}
</ul>
<button onClick={(e) => invert(e, Tool.TOOLBAR)} className="me-3">
{showToolBar ? <IconCaretUp /> : <IconCaretDown />}
</button>
</div>
{showToolBar && ( {showToolBar && (
<div className="p-1 flex justify-start items-center"> <nav className="flex justify-between pt-1 items-center">
<div className="flex justify-start items-center text-slate-800">
<Link to="/">
<img width={54} src={icon} alt="logo" className="ms-8" />
</Link>
<div className="ms-1 mt-1">
<div className="text-xl ms-3">Project1 / Untitled</div>
<div className="flex justify-between items-center">
<div className="flex justify-start text-md select-none me-2">
{Object.keys(menu).map((category) => (
<Dropdown
key={category}
style={{ width: "200px" }}
render={
<Dropdown.Menu>
{Object.keys(menu[category]).map((item, index) => {
if (menu[category][item].length > 0) {
return (
<Dropdown
style={{ width: "120px" }}
key={item}
position={"rightTop"}
render={
<Dropdown.Menu>
{menu[category][item].map((e) => (
<Dropdown.Item key={e}>
<div>{e}</div>
</Dropdown.Item>
))}
</Dropdown.Menu>
}
>
<Dropdown.Item
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center"
}}
>
<div>{item}</div>
<IconChevronRight />
</Dropdown.Item>
</Dropdown>
);
}
return (
<Dropdown.Item key={index}>
{item}
</Dropdown.Item>
);
})}
</Dropdown.Menu>
}
>
<div className="px-3 py-1 hover:bg-gray-100">
{category}
</div>
</Dropdown>
))}
</div>
<Button size="small" type="tertiary">
Last saved {new Date().toISOString()}
</Button>
</div>
</div>
</div>
<div className="flex justify-around items-center text-md me-8">
<AvatarGroup maxCount={3} size="default">
<Avatar color="red" alt="Lisa LeBlanc">
LL
</Avatar>
<Avatar color="green" alt="Caroline Xiao">
CX
</Avatar>
<Avatar color="amber" alt="Rafal Matin">
RM
</Avatar>
<Avatar alt="Zank Lance">ZL</Avatar>
<Avatar alt="Youself Zhang">YZ</Avatar>
</AvatarGroup>
<Button
type="primary"
style={{
fontSize: "16px",
marginLeft: "12px",
marginRight: "12px",
border: "1px solid white",
}}
size="large"
icon={<IconShareStroked />}
>
Share
</Button>
<Avatar size="default" alt="Buni Zhang">
BZ
</Avatar>
</div>
</nav>
)}
<div className="p-1 flex justify-between items-center rounded-xl bg-slate-100 my-1 mx-6 text-slate-700">
<div className="flex justify-start items-center">
<div className="relative"> <div className="relative">
<button className="ms-2 py-2 px-3 hover:bg-gray-300 relative">
<i className="fa-solid fa-table-list"></i>
</button>
<Divider layout="vertical" margin="8px" />
<button <button
className="ms-2 py-2 px-3 hover:bg-gray-300 relative" className="py-2 px-3 hover:bg-gray-300 relative"
onClick={(e) => invert(e, Tool.ZOOM)} onClick={(e) => invert(e, Tool.ZOOM)}
> >
zoom <IconCaretDown /> zoom <IconCaretdown />
</button> </button>
<ul <ul
className={`${ className={`${
@ -160,7 +219,8 @@ export default function ControlPanel() {
title="Add" title="Add"
onClick={(e) => invert(e, Tool.ADD)} onClick={(e) => invert(e, Tool.ADD)}
> >
<i className="fa-solid fa-plus"></i> <IconCaretDown /> <IconPlus />
<IconCaretdown />
</button> </button>
<ul <ul
className={`${ className={`${
@ -188,7 +248,10 @@ export default function ControlPanel() {
<i className="fa-solid fa-code-commit"></i> <i className="fa-solid fa-code-commit"></i>
</button> </button>
</div> </div>
)} <button onClick={(e) => invert(e, Tool.TOOLBAR)} className="me-3">
</nav> {showToolBar ? <IconChevronUp /> : <IconChevronDown />}
</button>
</div>
</>
); );
} }

View File

@ -1,11 +1,14 @@
import React from "react"; import React from "react";
import { Link } from "react-router-dom";
import blank_pfp from "../assets/blank_pfp.webp"; import blank_pfp from "../assets/blank_pfp.webp";
import logo from "../assets/logo_80.png"; import logo from "../assets/logo_80.png";
export default function Header(props) { export default function Header(props) {
return ( return (
<nav className="flex justify-between py-2 bg-blue text-white items-center"> <nav className="flex justify-between py-2 bg-blue text-white items-center">
<img width={136} src={logo} alt="logo" className="ms-8" /> <Link to="/">
<img width={136} src={logo} alt="logo" className="ms-8" />
</Link>
<div className="text-xl">{props.name}</div> <div className="text-xl">{props.name}</div>
<div className="flex justify-around items-center text-md me-8"> <div className="flex justify-around items-center text-md me-8">
<button className="me-6 border px-4 py-1 rounded-xl"> <button className="me-6 border px-4 py-1 rounded-xl">
@ -13,6 +16,7 @@ export default function Header(props) {
</button> </button>
<img src={blank_pfp} alt="profile" className="rounded-full h-8 w-8" /> <img src={blank_pfp} alt="profile" className="rounded-full h-8 w-8" />
</div> </div>
</nav> </nav>
); );
} }

View File

@ -8,7 +8,7 @@ export default function Relationship(props) {
const tableWidth = 240; const tableWidth = 240;
const midX = (x2 + x1 + tableWidth) / 2; const midX = (x2 + x1 + tableWidth) / 2;
const endX = x2 + tableWidth < x1 ? x2 + tableWidth - offsetX * 2 : x2; const endX = x2 + tableWidth < x1 ? x2 + tableWidth - offsetX * 2 : x2;
if (Math.abs(y1 - y2) <= 36) { if (Math.abs(y1 - y2) <= 36) {
r = Math.abs(y2 - y1) / 3; r = Math.abs(y2 - y1) / 3;
if (r <= 2) { if (r <= 2) {
@ -20,13 +20,13 @@ export default function Relationship(props) {
} }
if (y1 <= y2) { if (y1 <= y2) {
if (x1 + tableWidth < x2) { if (x1 + tableWidth <= x2) {
return `M ${x1 + tableWidth - offsetX * 2} ${y1} L ${ return `M ${x1 + tableWidth - offsetX * 2} ${y1} L ${
midX - r midX - r
} ${y1} A ${r} ${r} 0 0 1 ${midX} ${y1 + r} L ${midX} ${ } ${y1} A ${r} ${r} 0 0 1 ${midX} ${y1 + r} L ${midX} ${
y2 - r y2 - r
} A ${r} ${r} 0 0 0 ${midX + r} ${y2} L ${endX} ${y2}`; } A ${r} ${r} 0 0 0 ${midX + r} ${y2} L ${endX} ${y2}`;
} else if (x2 < x1 + tableWidth && x1 < x2) { } else if (x2 <= x1 + tableWidth && x1 <= x2) {
return `M ${x1 + tableWidth - 2 * offsetX} ${y1} L ${ return `M ${x1 + tableWidth - 2 * offsetX} ${y1} L ${
x2 + tableWidth x2 + tableWidth
} ${y1} A ${r} ${r} 0 0 1 ${x2 + tableWidth + r} ${y1 + r} L ${ } ${y1} A ${r} ${r} 0 0 1 ${x2 + tableWidth + r} ${y1 + r} L ${
@ -34,7 +34,7 @@ export default function Relationship(props) {
} ${y2 - r} A ${r} ${r} 0 0 1 ${x2 + tableWidth} ${y2} L ${ } ${y2 - r} A ${r} ${r} 0 0 1 ${x2 + tableWidth} ${y2} L ${
x2 + tableWidth - 2 * offsetX x2 + tableWidth - 2 * offsetX
} ${y2}`; } ${y2}`;
} else if (x2 + tableWidth > x1 && x2 + tableWidth < x1 + tableWidth) { } else if (x2 + tableWidth >= x1 && x2 + tableWidth <= x1 + tableWidth) {
return `M ${x1} ${y1} L ${x2 - r} ${y1} A ${r} ${r} 0 0 ${0} ${ return `M ${x1} ${y1} L ${x2 - r} ${y1} A ${r} ${r} 0 0 ${0} ${
x2 - r - r x2 - r - r
} ${y1 + r} L ${x2 - r - r} ${y2 - r} A ${r} ${r} 0 0 0 ${ } ${y1 + r} L ${x2 - r - r} ${y2 - r} A ${r} ${r} 0 0 0 ${
@ -48,19 +48,19 @@ export default function Relationship(props) {
} ${y2} L ${endX} ${y2}`; } ${y2} L ${endX} ${y2}`;
} }
} else { } else {
if (x1 + tableWidth < x2) { if (x1 + tableWidth <= x2) {
return `M ${x1 + tableWidth - offsetX * 2} ${y1} L ${ return `M ${x1 + tableWidth - offsetX * 2} ${y1} L ${
midX - r midX - r
} ${y1} A ${r} ${r} 0 0 0 ${midX} ${y1 - r} L ${midX} ${ } ${y1} A ${r} ${r} 0 0 0 ${midX} ${y1 - r} L ${midX} ${
y2 + r y2 + r
} A ${r} ${r} 0 0 1 ${midX + r} ${y2} L ${endX} ${y2}`; } A ${r} ${r} 0 0 1 ${midX + r} ${y2} L ${endX} ${y2}`;
} else if (x1 + tableWidth > x2 && x1 + tableWidth < x2 + tableWidth) { } else if (x1 + tableWidth >= x2 && x1 + tableWidth <= x2 + tableWidth) {
return `M ${x1} ${y1} L ${x1 - r} ${y1} A ${r} ${r} 0 0 1 ${ return `M ${x1} ${y1} L ${x1 - r} ${y1} A ${r} ${r} 0 0 1 ${
x1 - r - r x1 - r - r
} ${y1 - r} L ${x1 - r - r} ${y2 + r} A ${r} ${r} 0 0 1 ${ } ${y1 - r} L ${x1 - r - r} ${y2 + r} A ${r} ${r} 0 0 1 ${
x1 - r x1 - r
} ${y2} L ${endX} ${y2}`; } ${y2} L ${endX} ${y2}`;
} else if (x1 > x2 && x1 < x2 + tableWidth) { } else if (x1 >= x2 && x1 <= x2 + tableWidth) {
return `M ${x1 + tableWidth - 2 * offsetX} ${y1} L ${ return `M ${x1 + tableWidth - 2 * offsetX} ${y1} L ${
x1 + tableWidth - 2 * offsetX + r x1 + tableWidth - 2 * offsetX + r
} ${y1} A ${r} ${r} 0 0 0 ${x1 + tableWidth - 2 * offsetX + r + r} ${ } ${y1} A ${r} ${r} 0 0 0 ${x1 + tableWidth - 2 * offsetX + r + r} ${

View File

@ -99,6 +99,7 @@ const tableThemes = [
]; ];
const defaultTableTheme = "#9e9e9e"; const defaultTableTheme = "#9e9e9e";
const bgBlue = "#124559";
const Cardinality = { const Cardinality = {
ONE_TO_ONE: "One to one", ONE_TO_ONE: "One to one",
@ -115,4 +116,4 @@ const Constraint = {
setDefault: "Set default", setDefault: "Set default",
}; };
export { menu, sqlDataTypes, tableThemes, defaultTableTheme, Cardinality, Constraint }; export { menu, bgBlue, sqlDataTypes, tableThemes, defaultTableTheme, Cardinality, Constraint };

View File

@ -1,5 +1,4 @@
import React, { useState } from "react"; import React, { useState } from "react";
import Header from "../components/header";
import Sidebar from "../components/sidebar"; import Sidebar from "../components/sidebar";
import ControlPanel from "../components/control_panel"; import ControlPanel from "../components/control_panel";
import { DndProvider } from "react-dnd"; import { DndProvider } from "react-dnd";
@ -15,7 +14,6 @@ export default function Editor(props) {
return ( return (
<> <>
<Header name={props.name} />
<ControlPanel /> <ControlPanel />
<div className="flex h-full"> <div className="flex h-full">
<DndProvider backend={HTML5Backend}> <DndProvider backend={HTML5Backend}>