drawDB/src/pages/Templates.jsx

342 lines
13 KiB
React
Raw Normal View History

2023-12-23 09:16:54 +08:00
import { useEffect } from "react";
2024-02-28 22:53:59 +08:00
import logo_light from "../assets/logo_light_160.png";
2024-03-11 08:45:44 +08:00
import template_screenshot from "../assets/template_screenshot.png";
2023-11-30 15:18:41 +08:00
import { Link } from "react-router-dom";
import { Tabs, TabPane, Banner, Steps } from "@douyinfe/semi-ui";
2023-12-23 09:16:54 +08:00
import { IconDeleteStroked } from "@douyinfe/semi-icons";
2023-12-11 09:00:25 +08:00
import { db } from "../data/db";
2023-12-23 09:16:54 +08:00
import { useLiveQuery } from "dexie-react-hooks";
2024-03-11 08:45:44 +08:00
import { calcPath } from "../utils/calcPath";
2023-12-11 09:00:25 +08:00
2023-12-19 10:36:10 +08:00
function Thumbnail({ diagram, i }) {
2023-12-12 05:11:30 +08:00
const zoom = 0.3;
2023-12-11 09:00:25 +08:00
return (
2023-12-19 10:36:10 +08:00
<div className="w-full select-none">
2023-12-12 07:14:29 +08:00
<svg className="bg-white w-full h-full rounded-t-md">
2023-12-11 09:00:25 +08:00
<defs>
<pattern
2023-12-19 10:36:10 +08:00
id={"pattern-circles-" + i}
2023-12-11 09:00:25 +08:00
x="0"
y="0"
width="10"
height="10"
patternUnits="userSpaceOnUse"
patternContentUnits="userSpaceOnUse"
>
<circle
2023-12-19 10:36:10 +08:00
id={"pattern-circle-" + i}
2023-12-11 09:00:25 +08:00
cx="2"
cy="2"
r="0.4"
fill="rgb(99, 152, 191)"
></circle>
</pattern>
</defs>
<rect
x="0"
y="0"
width="100%"
height="100%"
2023-12-19 10:36:10 +08:00
fill={"url(#pattern-circles-" + i + ")"}
2023-12-11 09:00:25 +08:00
></rect>
2023-12-19 10:36:10 +08:00
<g>
2023-12-12 05:11:30 +08:00
{diagram.subjectAreas?.map((a) => (
<foreignObject
key={a.id}
x={a.x * zoom}
y={a.y * zoom}
width={a.width > 0 ? a.width * zoom : 0}
height={a.height > 0 ? a.height * zoom : 0}
>
<div
className={`border border-slate-400 w-full h-full rounded-sm relative`}
>
<div
className="opacity-40 w-fill h-full"
style={{ backgroundColor: a.color }}
/>
</div>
<div className="text-color absolute top-[4px] left-[6px] select-none text-[4px]">
{a.name}
</div>
</foreignObject>
))}
{diagram.tables?.map((table, i) => {
2023-12-11 09:00:25 +08:00
const height = table.fields.length * 36 + 50 + 7;
return (
<foreignObject
2023-12-12 05:11:30 +08:00
x={table.x * zoom}
y={table.y * zoom}
width={200 * zoom}
height={height * zoom}
2023-12-11 09:00:25 +08:00
key={i}
>
<div className="border-[1px] rounded-[3px] border-zinc-300 text-[4px] bg-zinc-100">
<div
className="h-[4px] w-full rounded-t-sm"
style={{ backgroundColor: table.color }}
></div>
<div className="rounded-b-[3px]">
<div className="bg-zinc-200 font-bold py-[2px] px-[4px] border-b border-gray-300">
{table.name}
</div>
{table.fields.map((f, j) => (
<div
2024-03-11 08:45:44 +08:00
className={`flex justify-between items-center py-[2px] px-[3px] ${
j < table.fields.length - 1 ? "border-b" : ""
}`}
2023-12-11 09:00:25 +08:00
key={j}
>
<div className="flex items-center justify-start">
<div
className={`w-[3px] h-[3px] bg-[#2f68ad] opacity-80 z-50 rounded-full me-[2px]`}
></div>
<div>{f.name}</div>
</div>
<div className="text-zinc-500">{f.type}</div>
</div>
))}
</div>
</div>
</foreignObject>
);
})}
2023-12-12 05:11:30 +08:00
{diagram.relationships?.map((e, i) => (
<path
2023-12-16 11:39:13 +08:00
key={i}
2024-03-11 08:45:44 +08:00
d={calcPath(e.startX, e.endX, e.startY, e.endY, zoom)}
2023-12-12 05:11:30 +08:00
fill="none"
strokeWidth={1}
stroke="gray"
/>
))}
{diagram.notes?.map((n) => {
const x = n.x * zoom;
const y = n.y * zoom;
const w = 180 * zoom;
const r = 3 * zoom;
const fold = 24 * zoom;
const h = n.height * zoom;
return (
2023-12-16 11:39:13 +08:00
<g key={n.id}>
2023-12-12 05:11:30 +08:00
<path
2024-03-11 08:45:44 +08:00
d={`M${x + fold} ${y} L${x + w - r} ${y} A${r} ${r} 0 0 1 ${
x + w
} ${y + r} L${x + w} ${y + h - r} A${r} ${r} 0 0 1 ${
x + w - r
} ${y + h} L${x + r} ${y + h} A${r} ${r} 0 0 1 ${x} ${
y + h - r
} L${x} ${y + fold}`}
2023-12-12 05:11:30 +08:00
fill={n.color}
stroke="rgb(168 162 158)"
strokeLinejoin="round"
strokeWidth="0.5"
/>
<path
2024-03-11 08:45:44 +08:00
d={`M${x} ${y + fold} L${x + fold - r} ${
y + fold
} A${r} ${r} 0 0 0 ${x + fold} ${y + fold - r} L${
x + fold
} ${y} L${x} ${y + fold} Z`}
2023-12-12 05:11:30 +08:00
fill={n.color}
stroke={"rgb(168 162 158)"}
strokeLinejoin="round"
strokeWidth="0.5"
/>
<foreignObject x={x} y={y} width={w} height={h}>
<div className="text-gray-900 w-full h-full px-[4px] py-[2px] text-[4px]">
<label htmlFor={`note_${n.id}`} className="ms-[6px]">
{n.title}
</label>
<div className="text-[4px] mt-[2px]">{n.content}</div>
</div>
</foreignObject>
</g>
);
})}
2023-12-11 09:00:25 +08:00
</g>
</svg>
</div>
);
}
2023-11-30 15:18:41 +08:00
export default function Templates() {
2023-12-23 09:16:54 +08:00
const defaultTemplates = useLiveQuery(() =>
db.templates.where({ custom: 0 }).toArray()
);
const customTemplates = useLiveQuery(() =>
db.templates.where({ custom: 1 }).toArray()
);
const deleteTemplate = async (id) => {
await db.templates.delete(id);
};
2023-12-11 09:00:25 +08:00
2023-12-24 09:06:49 +08:00
const editTemplate = (id) => {
2023-12-25 05:26:14 +08:00
const newWindow = window.open("/editor", "_blank");
newWindow.name = "t " + id;
2023-12-24 09:06:49 +08:00
};
2023-12-26 22:40:47 +08:00
const forkTemplate = (id) => {
const newWindow = window.open("/editor", "_blank");
newWindow.name = "lt " + id;
};
2023-12-11 09:00:25 +08:00
useEffect(() => {
document.title = "Templates | drawDB";
}, []);
2023-11-30 15:18:41 +08:00
return (
<div>
2023-12-12 07:14:29 +08:00
<div className="min-h-screen">
<div className="sm:py-3 py-5 px-12 xl:px-20 sm:px-6 flex justify-between items-center select-none">
<div className="flex items-center justify-start">
<Link to="/">
<img
src={logo_light}
alt="logo"
2024-02-28 22:53:59 +08:00
className="me-2 sm:h-[28px] md:h-[46px] h-[48px]"
2023-12-12 07:14:29 +08:00
/>
</Link>
<div className="ms-4 sm:text-sm xl:text-xl text-xl font-semibold">
Templates
</div>
2023-11-30 15:18:41 +08:00
</div>
</div>
2023-12-12 07:14:29 +08:00
<hr className="border-zinc-300" />
<div className="xl:px-20 sm:px-6 px-12 py-6">
<div className="w-full md:w-[75%] xl:w-[50%] mb-2">
<div className="text-2xl sm:text-lg font-semibold mb-2 text-neutral-800">
Database schema templates
</div>
<div className="text-sm text-neutral-700">
A compilation of database entity relationship diagrams to give you
2023-12-16 11:39:13 +08:00
a quick start or inspire your application&apos;s architecture.
2023-12-12 07:14:29 +08:00
</div>
2023-12-11 09:00:25 +08:00
</div>
2023-12-12 07:14:29 +08:00
<Tabs>
<TabPane
tab={<span className="mx-2">Default templates</span>}
itemKey="1"
>
2023-12-23 09:16:54 +08:00
<div className="grid xl:grid-cols-3 grid-cols-2 sm:grid-cols-1 gap-10 my-6">
2023-12-19 10:36:10 +08:00
{defaultTemplates?.map((t, i) => (
2023-12-12 07:14:29 +08:00
<div
key={i}
className="bg-gray-100 hover:translate-y-[-6px] transition-all duration-300 border rounded-md"
>
2023-12-19 10:36:10 +08:00
<Thumbnail diagram={t} i={"1" + i} />
2023-12-12 07:14:29 +08:00
<div className="px-4 py-3">
<div className="flex justify-between">
<div className="text-lg font-bold text-zinc-700">
{t.title}
</div>
2023-12-26 22:40:47 +08:00
<button
className="border rounded px-2 py-1 bg-white hover:bg-gray-200 transition-all duration-300"
onClick={() => forkTemplate(t.id)}
>
2023-12-12 07:14:29 +08:00
<i className="fa-solid fa-code-fork"></i>
</button>
</div>
<div>{t.description}</div>
</div>
</div>
))}
</div>
</TabPane>
<TabPane
tab={<span className="mx-2">Your templates</span>}
itemKey="2"
>
2024-03-11 08:45:44 +08:00
{customTemplates?.length > 0 ? (
<div className="grid xl:grid-cols-3 grid-cols-2 sm:grid-cols-1 gap-8 my-6">
{customTemplates?.map((c, i) => (
<div
key={i}
className="bg-gray-100 hover:translate-y-[-6px] transition-all duration-300 border rounded-md"
>
<Thumbnail diagram={c} i={"2" + i} />
<div className="px-4 py-3 w-full">
<div className="flex justify-between">
<div className="text-lg font-bold text-zinc-700">
{c.title}
</div>
2024-03-11 08:45:44 +08:00
<div>
<button
2024-03-11 08:45:44 +08:00
className="me-1 border rounded px-2 py-1 bg-white hover:bg-gray-200 transition-all duration-300"
onClick={() => forkTemplate(c.id)}
>
2024-03-11 08:45:44 +08:00
<i className="fa-solid fa-code-fork"></i>
</button>
</div>
2023-12-23 09:16:54 +08:00
</div>
2024-03-11 08:45:44 +08:00
<div className="flex justify-around mt-2">
<button
className="w-full text-center flex justify-center items-center border rounded px-2 py-1 bg-white hover:bg-gray-200 transition-all duration-300 text-blue-500"
onClick={() => editTemplate(c.id)}
>
<i className="bi bi-pencil-fill"></i>
<div className="ms-1.5 font-semibold">Edit</div>
</button>
<div className="border-l border-gray-300 mx-2" />
<button
className="w-full text-center flex justify-center items-center border rounded px-2 py-1 bg-white hover:bg-gray-200 transition-all duration-300 text-red-500"
onClick={() => deleteTemplate(c.id)}
>
<IconDeleteStroked />
<div className="ms-1.5 font-semibold">Delete</div>
</button>
</div>
2023-12-23 09:16:54 +08:00
</div>
2024-03-11 08:45:44 +08:00
</div>
))}
</div>
) : (
<div className="py-5">
<Banner
fullMode={false}
type="info"
bordered
icon={null}
closeIcon={null}
description={<div>You have no custom templates saved.</div>}
/>
<div className="grid grid-cols-5 sm:grid-cols-1 gap-4 place-content-center my-4">
<img
src={template_screenshot}
className="border col-span-3 sm:cols-span-1 rounded"
/>
2024-03-11 08:45:44 +08:00
<div className="col-span-2 sm:cols-span-1">
<div className="text-xl font-bold my-4">
How to save a template
2023-12-19 10:36:10 +08:00
</div>
2024-03-11 08:45:44 +08:00
<Steps direction="vertical" style={{ margin: "12px" }}>
<Steps.Step
title="Build a diagram"
description="Build the template in the editor"
/>
<Steps.Step
title="Save as template"
description="Editor > File > Save as template"
/>
<Steps.Step
title="Load a template"
description="Fork a template to build on"
/>
</Steps>
2023-12-19 10:36:10 +08:00
</div>
</div>
2024-03-11 08:45:44 +08:00
</div>
)}
2023-12-12 07:14:29 +08:00
</TabPane>
</Tabs>
2023-12-11 09:00:25 +08:00
</div>
2023-12-12 07:14:29 +08:00
</div>
<hr className="border-zinc-300 my-1" />
<div className="text-center text-sm py-3">
&copy; 2024 <strong>drawDB</strong> - All right reserved.
2023-12-11 09:00:25 +08:00
</div>
2023-11-30 15:18:41 +08:00
</div>
);
}