Manage layout

This commit is contained in:
1ilit 2023-09-19 15:48:34 +03:00
parent b0737e1a89
commit a2aa12f598
4 changed files with 322 additions and 195 deletions

View File

@ -22,9 +22,7 @@ import {
import { toPng, toJpeg, toSvg } from "html-to-image"; import { toPng, toJpeg, toSvg } from "html-to-image";
import { saveAs } from "file-saver"; import { saveAs } from "file-saver";
export default function ControlPanel() { export default function ControlPanel(props) {
const [showToolBar, setShowToolBar] = useState(true);
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const [dataUrl, setDataUrl] = useState(""); const [dataUrl, setDataUrl] = useState("");
const [filename, setFilename] = useState( const [filename, setFilename] = useState(
@ -249,157 +247,12 @@ export default function ControlPanel() {
return ( return (
<> <>
{showToolBar && ( {props.layout.header && (
<nav className="flex justify-between pt-1 items-center whitespace-nowrap"> header()
<div className="flex justify-start items-center text-slate-800">
<Link to="/">
<img
width={54}
src={icon}
alt="logo"
className="ms-8 min-w-[54px]"
/>
</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}
position="bottomLeft"
style={{ width: "200px" }}
render={
<Dropdown.Menu>
{Object.keys(menu[category]).map((item, index) => {
if (menu[category][item].children.length > 0) {
return (
<Dropdown
style={{ width: "120px" }}
key={item}
position={"rightTop"}
render={
<Dropdown.Menu>
{menu[category][item].children.map(
(e, i) => (
<Dropdown.Item
key={i}
onClick={Object.values(e)[0]}
>
{Object.keys(e)[0]}
</Dropdown.Item>
)
)}
</Dropdown.Menu>
}
>
<Dropdown.Item
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
onClick={menu[category][item].function}
>
{item}
<IconChevronRight />
</Dropdown.Item>
</Dropdown>
);
}
return (
<Dropdown.Item
key={index}
onClick={menu[category][item].function}
>
{item}
</Dropdown.Item>
);
})}
</Dropdown.Menu>
}
>
<div className="px-3 py-1 hover:bg-gray-100 rounded">
{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",
}}
size="large"
icon={<IconShareStroked />}
>
Share
</Button>
<Avatar size="default" alt="Buni Zhang">
BZ
</Avatar>
</div>
</nav>
)} )}
<div className="p-2 px-5 flex justify-between items-center rounded-xl bg-slate-100 my-1 mx-6 text-slate-700 select-none"> <div className="p-2 px-5 flex justify-between items-center rounded-xl bg-slate-100 my-1 mx-6 text-slate-700 select-none">
<div className="flex justify-start items-center"> <div className="flex justify-start items-center">
<Dropdown {layoutDropdown()}
position="bottomLeft"
style={{ width: "180px" }}
render={
<Dropdown.Menu>
<Dropdown.Item
icon={
showToolBar ? (
<IconCheckboxTick />
) : (
<div className="px-2"></div>
)
}
onClick={() => setShowToolBar((prev) => !prev)}
>
Header
</Dropdown.Item>
<Dropdown.Item icon={<IconCheckboxTick />}>
Overview
</Dropdown.Item>
<Dropdown.Item icon={<IconCheckboxTick />}>
Services
</Dropdown.Item>
<Dropdown.Divider />
<Dropdown.Item icon={<IconCheckboxTick />}>
Fullscreen
</Dropdown.Item>
</Dropdown.Menu>
}
trigger="click"
>
<div className="py-1 px-2 hover:bg-slate-200 rounded">
<i className="fa-solid fa-table-list"></i> <IconCaretdown />
</div>
</Dropdown>
<Divider layout="vertical" margin="8px" /> <Divider layout="vertical" margin="8px" />
<Dropdown <Dropdown
style={{ width: "180px" }} style={{ width: "180px" }}
@ -496,8 +349,12 @@ export default function ControlPanel() {
<i className="fa-solid fa-code-branch"></i> <i className="fa-solid fa-code-branch"></i>
</button> </button>
</div> </div>
<button onClick={(e) => setShowToolBar((prev) => !prev)}> <button
{showToolBar ? <IconChevronUp /> : <IconChevronDown />} onClick={(e) =>
props.setLayout((prev) => ({ ...prev, header: !prev.header }))
}
>
{props.layout.header ? <IconChevronUp /> : <IconChevronDown />}
</button> </button>
</div> </div>
<Modal <Modal
@ -537,4 +394,280 @@ export default function ControlPanel() {
</Modal> </Modal>
</> </>
); );
function header() {
return <nav className="flex justify-between pt-1 items-center whitespace-nowrap">
<div className="flex justify-start items-center text-slate-800">
<Link to="/">
<img
width={54}
src={icon}
alt="logo"
className="ms-8 min-w-[54px]" />
</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}
position="bottomLeft"
style={{ width: "200px" }}
render={<Dropdown.Menu>
{Object.keys(menu[category]).map((item, index) => {
if (menu[category][item].children.length > 0) {
return (
<Dropdown
style={{ width: "120px" }}
key={item}
position={"rightTop"}
render={<Dropdown.Menu>
{menu[category][item].children.map(
(e, i) => (
<Dropdown.Item
key={i}
onClick={Object.values(e)[0]}
>
{Object.keys(e)[0]}
</Dropdown.Item>
)
)}
</Dropdown.Menu>}
>
<Dropdown.Item
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
onClick={menu[category][item].function}
>
{item}
<IconChevronRight />
</Dropdown.Item>
</Dropdown>
);
}
return (
<Dropdown.Item
key={index}
onClick={menu[category][item].function}
>
{item}
</Dropdown.Item>
);
})}
</Dropdown.Menu>}
>
<div className="px-3 py-1 hover:bg-gray-100 rounded">
{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",
}}
size="large"
icon={<IconShareStroked />}
>
Share
</Button>
<Avatar size="default" alt="Buni Zhang">
BZ
</Avatar>
</div>
</nav>;
}
function layoutDropdown() {
return (
<Dropdown
position="bottomLeft"
style={{ width: "180px" }}
render={
<Dropdown.Menu>
<Dropdown.Item
icon={
props.layout.header ? (
<IconCheckboxTick />
) : (
<div className="px-2"></div>
)
}
onClick={() =>
props.setLayout((prev) => ({
...prev,
header: !prev.header,
}))
}
>
Header
</Dropdown.Item>
<Dropdown
position={"rightTop"}
render={
<Dropdown.Menu>
<Dropdown.Item
icon={
props.layout.tables ? (
<IconCheckboxTick />
) : (
<div className="px-2"></div>
)
}
onClick={() =>
props.setLayout((prev) => ({
...prev,
tables: !prev.tables,
}))
}
>
Tables
</Dropdown.Item>
<Dropdown.Item
icon={
props.layout.relationships ? (
<IconCheckboxTick />
) : (
<div className="px-2"></div>
)
}
onClick={() =>
props.setLayout((prev) => ({
...prev,
relationships: !prev.relationships,
}))
}
>
Relationships
</Dropdown.Item>
<Dropdown.Item
icon={
props.layout.issues ? (
<IconCheckboxTick />
) : (
<div className="px-2"></div>
)
}
onClick={() =>
props.setLayout((prev) => ({
...prev,
issues: !prev.issues,
}))
}
>
Issues
</Dropdown.Item>
<Dropdown.Item
icon={
props.layout.editor ? (
<IconCheckboxTick />
) : (
<div className="px-2"></div>
)
}
onClick={() =>
props.setLayout((prev) => ({
...prev,
editor: !prev.editor,
}))
}
>
Editor
</Dropdown.Item>
<Dropdown.Item
icon={
props.layout.shapes ? (
<IconCheckboxTick />
) : (
<div className="px-2"></div>
)
}
onClick={() =>
props.setLayout((prev) => ({
...prev,
shapes: !prev.shapes,
}))
}
>
Shapes
</Dropdown.Item>
</Dropdown.Menu>
}
>
<Dropdown.Item
icon={
props.layout.sidebar ? (
<IconCheckboxTick />
) : (
<div className="px-2"></div>
)
}
onClick={() =>
props.setLayout((prev) => ({
...prev,
sidebar: !prev.sidebar,
}))
}
>
Sidebar
</Dropdown.Item>
</Dropdown>
<Dropdown.Item
icon={
props.layout.services ? (
<IconCheckboxTick />
) : (
<div className="px-2"></div>
)
}
onClick={() =>
props.setLayout((prev) => ({
...prev,
services: !prev.services,
}))
}
>
Services
</Dropdown.Item>
<Dropdown.Divider />
<Dropdown.Item icon={<IconCheckboxTick />}>
Fullscreen
</Dropdown.Item>
</Dropdown.Menu>
}
trigger="click"
>
<div className="py-1 px-2 hover:bg-slate-200 rounded">
<i className="fa-solid fa-table-list"></i> <IconCaretdown />
</div>
</Dropdown>
);
}
} }

View File

@ -5,7 +5,7 @@ export default function Relationship(props) {
const calcPath = (x1, x2, y1, y2) => { const calcPath = (x1, x2, y1, y2) => {
let r = 16; let r = 16;
const offsetX = 8; const offsetX = 8;
const tableWidth = 240; const tableWidth = 220;
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;

View File

@ -93,7 +93,7 @@ export default function Table(props) {
key={props.id} key={props.id}
x={props.tableData.x} x={props.tableData.x}
y={props.tableData.y} y={props.tableData.y}
width={240} width={220}
height={height} height={height}
style={{ cursor: "move" }} style={{ cursor: "move" }}
onMouseDown={props.onMouseDown} onMouseDown={props.onMouseDown}
@ -111,34 +111,15 @@ export default function Table(props) {
<div <div
className={`border-2 ${ className={`border-2 ${
isHovered ? "border-sky-500" : "border-gray-500" isHovered ? "border-sky-500" : "border-gray-500"
} bg-gray-300 select-none rounded-md`} } bg-gray-200 select-none rounded-md`}
> >
<div <div
style={{ backgroundColor: props.tableData.color }} // style={{ backgroundColor: props.tableData.color }}
className={`p-3 font-bold text-slate-800 h-[40px] rounded-t-md flex justify-between items-center`} className="p-3 bg-gray-300 font-bold text-slate-800 h-[40px] rounded-t-md flex justify-between items-center"
> >
{ <div className="p-1">
<form {props.tableData.name}
onSubmit={(e) => e.preventDefault()} </div>
onMouseEnter={() =>
props.setOnRect({
tableId: props.id,
field: -1,
})
}
>
<div
// type="text"
// value={name}
// onChange={(e) => setName(e.target.value)}
className={`p-1 select-text w-[100px] bg-gray-400 focus:bg-gray-200 ${
false
? "ring-2 ring-red-600"
: "focus:ring-2 focus:ring-sky-500 "
}`}
>{props.tableData.name}</div>
</form>
}
{isHovered && ( {isHovered && (
<div className="flex justify-end items-center"> <div className="flex justify-end items-center">
<button className="btn bg-sky-800 text-white text-xs py-1 px-2 me-2 opacity-80"> <button className="btn bg-sky-800 text-white text-xs py-1 px-2 me-2 opacity-80">
@ -499,3 +480,4 @@ export default function Table(props) {
</g> </g>
); );
} }

View File

@ -13,6 +13,16 @@ export default function Editor(props) {
const [areas, setAreas] = useState([]); const [areas, setAreas] = useState([]);
const [resize, setResize] = useState(false); const [resize, setResize] = useState(false);
const [width, setWidth] = useState(340); const [width, setWidth] = useState(340);
const [layout, setLayout] = useState({
header: true,
sidebar: true,
services: true,
tables: true,
relationships: true,
issues: true,
editor: true,
shapes: true,
});
const dragHandler = (e) => { const dragHandler = (e) => {
if (!resize) return; if (!resize) return;
@ -22,26 +32,28 @@ export default function Editor(props) {
return ( return (
<> <>
<ControlPanel /> <ControlPanel layout={layout} setLayout={setLayout} />
<div <div
className={`flex h-full`} className={`flex h-full`}
onMouseUp={() => setResize(false)} onMouseUp={() => setResize(false)}
onMouseMove={dragHandler} onMouseMove={dragHandler}
> >
<DndProvider backend={HTML5Backend}> <DndProvider backend={HTML5Backend}>
<EditorPanel {layout.sidebar && (
tables={tables} <EditorPanel
setTables={setTables} tables={tables}
code={code} setTables={setTables}
setCode={setCode} code={code}
relationships={relationships} setCode={setCode}
setRelationships={setRelationships} relationships={relationships}
areas={areas} setRelationships={setRelationships}
setAreas={setAreas} areas={areas}
resize={resize} setAreas={setAreas}
setResize={setResize} resize={resize}
width={width} setResize={setResize}
/> width={width}
/>
)}
<Canvas <Canvas
tables={tables} tables={tables}
setTables={setTables} setTables={setTables}
@ -53,7 +65,7 @@ export default function Editor(props) {
setAreas={setAreas} setAreas={setAreas}
/> />
</DndProvider> </DndProvider>
<Sidebar /> {layout.services && <Sidebar />}
</div> </div>
</> </>
); );