mirror of
https://github.com/drawdb-io/drawdb.git
synced 2026-02-12 02:00:40 +08:00
Clean up tabs
This commit is contained in:
101
src/components/EditorSidePanel/AreasTab/AreaDetails.jsx
Normal file
101
src/components/EditorSidePanel/AreasTab/AreaDetails.jsx
Normal file
@@ -0,0 +1,101 @@
|
||||
import { useState } from "react";
|
||||
import { Row, Col, Button, Input, Popover, Toast } from "@douyinfe/semi-ui";
|
||||
import { IconDeleteStroked } from "@douyinfe/semi-icons";
|
||||
import { useAreas, useSaveState, useUndoRedo } from "../../../hooks";
|
||||
import {
|
||||
Action,
|
||||
ObjectType,
|
||||
State,
|
||||
defaultBlue,
|
||||
} from "../../../data/constants";
|
||||
import ColorPallete from "../../ColorPallete";
|
||||
|
||||
export default function AreaInfo({ data, i }) {
|
||||
const { setSaveState } = useSaveState();
|
||||
const { deleteArea, updateArea } = useAreas();
|
||||
const { setUndoStack, setRedoStack } = useUndoRedo();
|
||||
const [editField, setEditField] = useState({});
|
||||
|
||||
return (
|
||||
<Row
|
||||
gutter={6}
|
||||
type="flex"
|
||||
justify="start"
|
||||
align="middle"
|
||||
id={`scroll_area_${data.id}`}
|
||||
className="my-3"
|
||||
>
|
||||
<Col span={18}>
|
||||
<Input
|
||||
value={data.name}
|
||||
placeholder="Name"
|
||||
onChange={(value) => updateArea(data.id, { name: value })}
|
||||
onFocus={(e) => setEditField({ name: e.target.value })}
|
||||
onBlur={(e) => {
|
||||
if (e.target.value === editField.name) return;
|
||||
setUndoStack((prev) => [
|
||||
...prev,
|
||||
{
|
||||
action: Action.EDIT,
|
||||
element: ObjectType.AREA,
|
||||
aid: i,
|
||||
undo: editField,
|
||||
redo: { name: e.target.value },
|
||||
message: `Edit area name to ${e.target.value}`,
|
||||
},
|
||||
]);
|
||||
setRedoStack([]);
|
||||
}}
|
||||
/>
|
||||
</Col>
|
||||
<Col span={3}>
|
||||
<Popover
|
||||
content={
|
||||
<div className="popover-theme">
|
||||
<ColorPallete
|
||||
currentColor={data.color}
|
||||
onClearColor={() => {
|
||||
updateArea(i, { color: defaultBlue });
|
||||
setSaveState(State.SAVING);
|
||||
}}
|
||||
onPickColor={(c) => {
|
||||
setUndoStack((prev) => [
|
||||
...prev,
|
||||
{
|
||||
action: Action.EDIT,
|
||||
element: ObjectType.AREA,
|
||||
aid: i,
|
||||
undo: { color: data.color },
|
||||
redo: { color: c },
|
||||
message: `Edit area color to ${c}`,
|
||||
},
|
||||
]);
|
||||
setRedoStack([]);
|
||||
updateArea(i, { color: c });
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
trigger="click"
|
||||
position="bottomLeft"
|
||||
showArrow
|
||||
>
|
||||
<div
|
||||
className="h-[32px] w-[32px] rounded"
|
||||
style={{ backgroundColor: data.color }}
|
||||
/>
|
||||
</Popover>
|
||||
</Col>
|
||||
<Col span={3}>
|
||||
<Button
|
||||
icon={<IconDeleteStroked />}
|
||||
type="danger"
|
||||
onClick={() => {
|
||||
Toast.success(`Area deleted!`);
|
||||
deleteArea(i, true);
|
||||
}}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
37
src/components/EditorSidePanel/AreasTab/AreasTab.jsx
Normal file
37
src/components/EditorSidePanel/AreasTab/AreasTab.jsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import { Row, Col, Button } from "@douyinfe/semi-ui";
|
||||
import { IconPlus } from "@douyinfe/semi-icons";
|
||||
import Empty from "../Empty";
|
||||
import { useAreas } from "../../../hooks";
|
||||
import SearchBar from "./SearchBar";
|
||||
import AreaInfo from "./AreaDetails";
|
||||
|
||||
export default function AreasTab() {
|
||||
const { areas, addArea } = useAreas();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Row gutter={6}>
|
||||
<Col span={16}>
|
||||
<SearchBar />
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
<Button icon={<IconPlus />} block onClick={addArea}>
|
||||
Add area
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
{areas.length <= 0 ? (
|
||||
<Empty
|
||||
title="No subject areas"
|
||||
text="Add subject areas to organize tables!"
|
||||
/>
|
||||
) : (
|
||||
<div className="p-2">
|
||||
{areas.map((a, i) => (
|
||||
<AreaInfo data={a} key={"area_" + i} i={i} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
39
src/components/EditorSidePanel/AreasTab/SearchBar.jsx
Normal file
39
src/components/EditorSidePanel/AreasTab/SearchBar.jsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import { useState } from "react";
|
||||
import { useAreas } from "../../../hooks";
|
||||
import { AutoComplete } from "@douyinfe/semi-ui";
|
||||
import { IconSearch } from "@douyinfe/semi-icons";
|
||||
|
||||
export default function SearchBar() {
|
||||
const { areas } = useAreas();
|
||||
const [searchText, setSearchText] = useState("");
|
||||
|
||||
const [filteredResult, setFilteredResult] = useState(
|
||||
areas.map((t) => t.name)
|
||||
);
|
||||
|
||||
const handleStringSearch = (value) => {
|
||||
setFilteredResult(
|
||||
areas.map((t) => t.name).filter((i) => i.includes(value))
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<AutoComplete
|
||||
data={filteredResult}
|
||||
value={searchText}
|
||||
showClear
|
||||
prefix={<IconSearch />}
|
||||
placeholder="Search..."
|
||||
emptyContent={<div className="p-3 popover-theme">No areas found</div>}
|
||||
onSearch={(v) => handleStringSearch(v)}
|
||||
onChange={(v) => setSearchText(v)}
|
||||
onSelect={(v) => {
|
||||
const { id } = areas.find((t) => t.name === v);
|
||||
document
|
||||
.getElementById(`scroll_area_${id}`)
|
||||
.scrollIntoView({ behavior: "smooth" });
|
||||
}}
|
||||
className="w-full"
|
||||
/>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user