This commit is contained in:
1ilit 2024-04-06 04:59:18 +03:00
commit c5cdcba459
7 changed files with 386 additions and 392 deletions

View File

@ -25,11 +25,11 @@ export default function WorkSpace() {
const [width, setWidth] = useState(340); const [width, setWidth] = useState(340);
const [lastSaved, setLastSaved] = useState(""); const [lastSaved, setLastSaved] = useState("");
const { layout } = useLayout(); const { layout } = useLayout();
const { settings } = useSettings();
const { types, setTypes } = useTypes(); const { types, setTypes } = useTypes();
const { areas, setAreas } = useAreas(); const { areas, setAreas } = useAreas();
const { tasks, setTasks } = useTasks(); const { tasks, setTasks } = useTasks();
const { notes, setNotes } = useNotes(); const { notes, setNotes } = useNotes();
const { settings, setSettings } = useSettings();
const { saveState, setSaveState } = useSaveState(); const { saveState, setSaveState } = useSaveState();
const { transform, setTransform } = useTransform(); const { transform, setTransform } = useTransform();
const { tables, relationships, setTables, setRelationships } = useTables(); const { tables, relationships, setTables, setRelationships } = useTables();
@ -41,6 +41,200 @@ export default function WorkSpace() {
if (w > 340) setWidth(w); if (w > 340) setWidth(w);
}; };
const save = useCallback(async () => {
const name = window.name.split(" ");
const op = name[0];
const saveAsDiagram = window.name === "" || op === "d" || op === "lt";
if (saveAsDiagram) {
if (
(id === 0 && window.name === "") ||
window.name.split(" ")[0] === "lt"
) {
await db.diagrams
.add({
name: title,
lastModified: new Date(),
tables: tables,
references: relationships,
types: types,
notes: notes,
areas: areas,
todos: tasks,
pan: transform.pan,
zoom: transform.zoom,
})
.then((id) => {
setId(id);
window.name = `d ${id}`;
setSaveState(State.SAVED);
setLastSaved(new Date().toLocaleString());
});
} else {
await db.diagrams
.update(id, {
name: title,
lastModified: new Date(),
tables: tables,
references: relationships,
types: types,
notes: notes,
areas: areas,
todos: tasks,
pan: transform.pan,
zoom: transform.zoom,
})
.then(() => {
setSaveState(State.SAVED);
setLastSaved(new Date().toLocaleString());
});
}
} else {
await db.templates
.update(id, {
title: title,
tables: tables,
relationships: relationships,
types: types,
notes: notes,
subjectAreas: areas,
todos: tasks,
pan: transform.pan,
zoom: transform.zoom,
})
.then(() => {
setSaveState(State.SAVED);
setLastSaved(new Date().toLocaleString());
})
.catch(() => {
setSaveState(State.ERROR);
});
}
}, [
tables,
relationships,
notes,
areas,
types,
title,
id,
tasks,
transform,
setSaveState,
]);
const load = useCallback(async () => {
const loadLatestDiagram = async () => {
await db.diagrams
.orderBy("lastModified")
.last()
.then((d) => {
if (d) {
setId(d.id);
setTables(d.tables);
setRelationships(d.references);
setNotes(d.notes);
setAreas(d.areas);
setTypes(d.types);
setTasks(d.todos ?? []);
setTransform({ pan: d.pan, zoom: d.zoom });
window.name = `d ${d.id}`;
} else {
window.name = "";
}
})
.catch((error) => {
console.log(error);
});
};
const loadDiagram = async (id) => {
await db.diagrams
.get(id)
.then((diagram) => {
if (diagram) {
setId(diagram.id);
setTitle(diagram.name);
setTables(diagram.tables);
setTypes(diagram.types);
setRelationships(diagram.references);
setAreas(diagram.areas);
setNotes(diagram.notes);
setTasks(diagram.todos ?? []);
setTransform({
pan: diagram.pan,
zoom: diagram.zoom,
});
setUndoStack([]);
setRedoStack([]);
window.name = `d ${diagram.id}`;
} else {
window.name = "";
}
})
.catch((error) => {
console.log(error);
});
};
const loadTemplate = async (id) => {
await db.templates
.get(id)
.then((diagram) => {
if (diagram) {
setId(diagram.id);
setTitle(diagram.title);
setTables(diagram.tables);
setTypes(diagram.types);
setRelationships(diagram.relationships);
setAreas(diagram.subjectAreas);
setTasks(diagram.todos ?? []);
setNotes(diagram.notes);
setTransform({
zoom: 1,
pan: { x: 0, y: 0 },
});
setUndoStack([]);
setRedoStack([]);
}
})
.catch((error) => {
console.log(error);
});
};
if (window.name === "") {
loadLatestDiagram();
} else {
const name = window.name.split(" ");
const op = name[0];
const id = parseInt(name[1]);
switch (op) {
case "d": {
loadDiagram(id);
break;
}
case "t":
case "lt": {
loadTemplate(id);
break;
}
default:
break;
}
}
}, [
setTransform,
setRedoStack,
setUndoStack,
setRelationships,
setTables,
setAreas,
setNotes,
setTypes,
setTasks,
]);
useEffect(() => { useEffect(() => {
if ( if (
tables?.length === 0 && tables?.length === 0 &&
@ -69,217 +263,17 @@ export default function WorkSpace() {
setSaveState, setSaveState,
]); ]);
const save = useCallback(
async (diagram = true) => {
if (saveState !== State.SAVING) {
return;
}
if (diagram) {
if (
(id === 0 && window.name === "") ||
window.name.split(" ")[0] === "lt"
) {
db.diagrams
.add({
name: title,
lastModified: new Date(),
tables: tables,
references: relationships,
types: types,
notes: notes,
areas: areas,
todos: tasks,
pan: transform.pan,
zoom: transform.zoom,
})
.then((id) => {
setId(id);
window.name = `d ${id}`;
setSaveState(State.SAVED);
setLastSaved(new Date().toLocaleString());
});
} else {
db.diagrams
.update(id, {
name: title,
lastModified: new Date(),
tables: tables,
references: relationships,
types: types,
notes: notes,
areas: areas,
todos: tasks,
pan: transform.pan,
zoom: transform.zoom,
})
.then(() => {
setSaveState(State.SAVED);
setLastSaved(new Date().toLocaleString());
});
}
} else {
db.templates
.update(id, {
title: title,
tables: tables,
relationships: relationships,
types: types,
notes: notes,
subjectAreas: areas,
todos: tasks,
pan: transform.pan,
zoom: transform.zoom,
})
.then(() => {
setSaveState(State.SAVED);
setLastSaved(new Date().toLocaleString());
})
.catch(() => {
setSaveState(State.ERROR);
});
}
},
[
tables,
relationships,
notes,
areas,
types,
title,
id,
saveState,
tasks,
transform.zoom,
transform.pan,
setSaveState,
]
);
useEffect(() => { useEffect(() => {
const name = window.name.split(" "); if (saveState !== State.SAVING) return;
const op = name[0];
const diagram = window.name === "" || op === "d" || op === "lt";
save(diagram); save();
}, [id, saveState, save]); }, [id, saveState, save]);
useEffect(() => { useEffect(() => {
document.title = "Editor | drawDB"; document.title = "Editor | drawDB";
const loadLatestDiagram = async () => { load();
db.diagrams }, [load]);
.orderBy("lastModified")
.last()
.then((d) => {
if (d) {
setId(d.id);
setTables(d.tables);
setRelationships(d.references);
setNotes(d.notes);
setAreas(d.areas);
setTypes(d.types);
setTasks(d.todos ?? []);
setTransform({ pan: d.pan, zoom: d.zoom });
window.name = `d ${d.id}`;
} else {
window.name = "";
}
})
.catch((error) => {
console.log(error);
});
};
const loadDiagram = async (id) => {
db.diagrams
.get(id)
.then((diagram) => {
if (diagram) {
setId(diagram.id);
setTitle(diagram.name);
setTables(diagram.tables);
setTypes(diagram.types);
setRelationships(diagram.references);
setAreas(diagram.areas);
setNotes(diagram.notes);
setTasks(diagram.todos ?? []);
setTransform({
pan: diagram.pan,
zoom: diagram.zoom,
});
setUndoStack([]);
setRedoStack([]);
window.name = `d ${diagram.id}`;
} else {
window.name = "";
}
})
.catch((error) => {
console.log(error);
});
};
const loadTemplate = async (id) => {
db.templates
.get(id)
.then((diagram) => {
if (diagram) {
setId(diagram.id);
setTitle(diagram.title);
setTables(diagram.tables);
setTypes(diagram.types);
setRelationships(diagram.relationships);
setAreas(diagram.subjectAreas);
setTasks(diagram.todos ?? []);
setNotes(diagram.notes);
setTransform({
zoom: 1,
pan: { x: 0, y: 0 },
});
setUndoStack([]);
setRedoStack([]);
}
})
.catch((error) => {
console.log(error);
});
};
if (window.name == "") {
console.log("Loading the latest diagram");
loadLatestDiagram();
} else {
const name = window.name.split(" ");
const op = name[0];
const did = parseInt(name[1]);
switch (op) {
case "d": {
loadDiagram(did);
break;
}
case "lt": {
loadTemplate(did);
break;
}
case "t": {
loadTemplate(did);
break;
}
default:
break;
}
}
}, [
setSettings,
setTransform,
setRedoStack,
setUndoStack,
setRelationships,
setTables,
setAreas,
setNotes,
setTypes,
setTasks,
]);
return ( return (
<div className="h-[100vh] flex flex-col overflow-hidden theme"> <div className="h-[100vh] flex flex-col overflow-hidden theme">

48
src/data/shortcuts.js Normal file
View File

@ -0,0 +1,48 @@
export const shortcuts = [
{ shortcut: "CTRL+S", title: "Save diagram", description: "" },
{ shortcut: "CTRL+Shift+S", title: "Save diagram as", description: "" },
{
shortcut: "CTRL+O",
title: "Open a diagram",
description: "Load a saved diagram",
},
{ shortcut: "CTRL+C", title: "Copy selected element", description: "" },
{ shortcut: "CTRL+V", title: "Paste selected element", description: "" },
{ shortcut: "CTRL+X", title: "Cut selected element", description: "" },
{ shortcut: "CTRL+D", title: "Duplicate selected element", description: "" },
{ shortcut: "DEL", title: "Delete selected element", description: "" },
{ shortcut: "CTRL+E", title: "Edit selected element", description: "" },
{
shortcut: "CTRL+I",
title: "Import a diagram",
description: "Import a diagram by uploadng a valid json or dbb file.",
},
{ shortcut: "CTRL+Z", title: "Undo" },
{ shortcut: "CTRL+Y", title: "Redo" },
{
shortcut: "CTRL+SHIFT+M",
title: "Enable/disable strict mode",
description:
"Disabling strict mode entails that the diagram will not undergo error or inconsistency checks.",
},
{
shortcut: "CTRL+SHIFT+F",
title: "Enable/disable field summaries",
description:
"Disabling field summaries will prevent the display of details for each field in the table when hovered over.",
},
{ shortcut: "CTRL+SHIFT+G", title: "Show/hide grid" },
{
shortcut: "CTRL+ALT+C",
title: "Copy as image",
description: "Save the canvas as an image to the clipboard.",
},
{
shortcut: "CTRL+R",
title: "Reset view",
description: "Resetting view will set diagram pan to (0, 0).",
},
{ shortcut: "CTRL+UP / Wheel up", title: "Zoom in" },
{ shortcut: "CTRL+DOWN / Wheel down", title: "Zoom out" },
{ shortcut: "CTRL+H", title: "Open shortcuts" },
];

View File

@ -0,0 +1,10 @@
export const questions = {
satisfaction: "How satisfied are you with drawDB?",
ease: "How easy was it to get started with drawDB?",
wouldRecommend: "How likely are you to recommend drawDB?",
hadDifficulty: "Did you encounter any difficulties when navigating drawDB?",
difficulty: "What were the difficulties you faced?",
triedOtherApps: "Have you tried apps like drawDB?",
comparison: "How did you find drawDB as compared to other apps?",
occupation: "What is your occupation?",
};

View File

@ -14,127 +14,6 @@ import discord from "../assets/discord.png";
import FadeIn from "../animations/FadeIn"; import FadeIn from "../animations/FadeIn";
import SlideIn from "../animations/SlideIn"; import SlideIn from "../animations/SlideIn";
const features = [
{
title: "Export",
content: (
<div>
Export the DDL script to run on your database or export the diagram as a
JSON or an image.
</div>
),
footer: "",
},
{
title: "Import",
content: (
<div>
Already have a diagram? Import a DDL script*, or a JSON file to generate
or a diagram.
</div>
),
footer: "*Only MySQL supported, more coming soon.",
},
{
title: "Customizable workspace",
content: (
<div>
Customize the UI to fit your preferences. Select the components you want
in your view.
</div>
),
footer: "",
},
{
title: "Keyboard shortcuts",
content: (
<div>
Speed up development with keyboard shortuts. See all available shortcuts
<Link to="/shortcuts" className="ms-1.5 text-blue-500 hover:underline">
here
</Link>
.
</div>
),
footer: "",
},
{
title: "Templates",
content: (
<div>
Start off with pre-built templates. Get a quick start or get inspirition
for your design.
</div>
),
footer: "",
},
{
title: "Custom Templates",
content: (
<div>
Have boilerplate structures? Save time by saving them as templates and
load them when needed.
</div>
),
footer: "",
},
{
title: "Robust editor",
content: (
<div>
Undo, redo, copy, paste, duplacate and more. Add tables, subject areas,
and notes.
</div>
),
footer: "",
},
{
title: "Issue detection",
content: (
<div>
Detect and tackle errors in the diagram to make sure the scripts are
correct.
</div>
),
footer: "",
},
{
title: "Relational databases",
content: (
<div>
We support 5 relational databases - MySQL, PostgreSQL, SQLite, MariaDB,
SQL Server.
</div>
),
footer: "",
},
{
title: "Object-Relational databases",
content: (
<div>
Add custom types for object-relational databases, or create custom JSON
schemes and alias types.
</div>
),
footer: "",
},
{
title: "Presentation mode",
content: (
<div>
Present your diagrams on a big screen during team meetings and
discussions.
</div>
),
footer: "",
},
{
title: "Track todos",
content: <div>Keep track of tasks and mark them done when finished.</div>,
footer: "",
},
];
export default function LandingPage() { export default function LandingPage() {
const [showSurvey, setShowSurvey] = useState(true); const [showSurvey, setShowSurvey] = useState(true);
@ -379,3 +258,124 @@ export default function LandingPage() {
</div> </div>
); );
} }
const features = [
{
title: "Export",
content: (
<div>
Export the DDL script to run on your database or export the diagram as a
JSON or an image.
</div>
),
footer: "",
},
{
title: "Import",
content: (
<div>
Already have a diagram? Import a DDL script*, or a JSON file to generate
or a diagram.
</div>
),
footer: "*Only MySQL supported, more coming soon.",
},
{
title: "Customizable workspace",
content: (
<div>
Customize the UI to fit your preferences. Select the components you want
in your view.
</div>
),
footer: "",
},
{
title: "Keyboard shortcuts",
content: (
<div>
Speed up development with keyboard shortuts. See all available shortcuts
<Link to="/shortcuts" className="ms-1.5 text-blue-500 hover:underline">
here
</Link>
.
</div>
),
footer: "",
},
{
title: "Templates",
content: (
<div>
Start off with pre-built templates. Get a quick start or get inspirition
for your design.
</div>
),
footer: "",
},
{
title: "Custom Templates",
content: (
<div>
Have boilerplate structures? Save time by saving them as templates and
load them when needed.
</div>
),
footer: "",
},
{
title: "Robust editor",
content: (
<div>
Undo, redo, copy, paste, duplacate and more. Add tables, subject areas,
and notes.
</div>
),
footer: "",
},
{
title: "Issue detection",
content: (
<div>
Detect and tackle errors in the diagram to make sure the scripts are
correct.
</div>
),
footer: "",
},
{
title: "Relational databases",
content: (
<div>
We support 5 relational databases - MySQL, PostgreSQL, SQLite, MariaDB,
SQL Server.
</div>
),
footer: "",
},
{
title: "Object-Relational databases",
content: (
<div>
Add custom types for object-relational databases, or create custom JSON
schemes and alias types.
</div>
),
footer: "",
},
{
title: "Presentation mode",
content: (
<div>
Present your diagrams on a big screen during team meetings and
discussions.
</div>
),
footer: "",
},
{
title: "Track todos",
content: <div>Keep track of tasks and mark them done when finished.</div>,
footer: "",
},
];

View File

@ -4,55 +4,7 @@ import logo_dark from "../assets/logo_dark_160.png";
import { AutoComplete, Button } from "@douyinfe/semi-ui"; import { AutoComplete, Button } from "@douyinfe/semi-ui";
import { IconSearch, IconSun, IconMoon } from "@douyinfe/semi-icons"; import { IconSearch, IconSun, IconMoon } from "@douyinfe/semi-icons";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { shortcuts } from "../data/shortcuts";
const shortcuts = [
{ shortcut: "CTRL+S", title: "Save diagram", description: "" },
{ shortcut: "CTRL+Shift+S", title: "Save diagram as", description: "" },
{
shortcut: "CTRL+O",
title: "Open a diagram",
description: "Load a saved diagram",
},
{ shortcut: "CTRL+C", title: "Copy selected element", description: "" },
{ shortcut: "CTRL+V", title: "Paste selected element", description: "" },
{ shortcut: "CTRL+X", title: "Cut selected element", description: "" },
{ shortcut: "CTRL+D", title: "Duplicate selected element", description: "" },
{ shortcut: "DEL", title: "Delete selected element", description: "" },
{ shortcut: "CTRL+E", title: "Edit selected element", description: "" },
{
shortcut: "CTRL+I",
title: "Import a diagram",
description: "Import a diagram by uploadng a valid json or dbb file.",
},
{ shortcut: "CTRL+Z", title: "Undo" },
{ shortcut: "CTRL+Y", title: "Redo" },
{
shortcut: "CTRL+SHIFT+M",
title: "Enable/disable strict mode",
description:
"Disabling strict mode entails that the diagram will not undergo error or inconsistency checks.",
},
{
shortcut: "CTRL+SHIFT+F",
title: "Enable/disable field summaries",
description:
"Disabling field summaries will prevent the display of details for each field in the table when hovered over.",
},
{ shortcut: "CTRL+SHIFT+G", title: "Show/hide grid" },
{
shortcut: "CTRL+ALT+C",
title: "Copy as image",
description: "Save the canvas as an image to the clipboard.",
},
{
shortcut: "CTRL+R",
title: "Reset view",
description: "Resetting view will set diagram pan to (0, 0).",
},
{ shortcut: "CTRL+UP / Wheel up", title: "Zoom in" },
{ shortcut: "CTRL+DOWN / Wheel down", title: "Zoom out" },
{ shortcut: "CTRL+H", title: "Open shortcuts" },
];
export default function Shortcuts() { export default function Shortcuts() {
const [theme, setTheme] = useState(""); const [theme, setTheme] = useState("");

View File

@ -1,4 +1,4 @@
import { useEffect, useState, useCallback, useMemo } from "react"; import { useEffect, useState, useCallback } from "react";
import logo_light from "../assets/logo_light_160.png"; import logo_light from "../assets/logo_light_160.png";
import logo_dark from "../assets/logo_dark_160.png"; import logo_dark from "../assets/logo_dark_160.png";
import { import {
@ -21,23 +21,10 @@ import { CLEAR_EDITOR_COMMAND } from "lexical";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import RichEditor from "../components/LexicalEditor/RichEditor"; import RichEditor from "../components/LexicalEditor/RichEditor";
import axios from "axios"; import axios from "axios";
import { questions } from "../data/surveyQuestions";
function SurveyForm({ theme }) { function SurveyForm({ theme }) {
const [editor] = useLexicalComposerContext(); const [editor] = useLexicalComposerContext();
const questions = useMemo(
() => ({
satisfaction: "How satisfied are you with drawDB?",
ease: "How easy was it to get started with drawDB?",
wouldRecommend: "How likely are you to recommend drawDB?",
hadDifficulty:
"Did you encounter any difficulties when navigating drawDB?",
difficulty: "What were the difficulties you faced?",
triedOtherApps: "Have you tried apps like drawDB?",
comparison: "How did you find drawDB as compared to other apps?",
occupation: "What is your occupation?",
}),
[]
);
const [form, setForm] = useState({ const [form, setForm] = useState({
satisfaction: 5, satisfaction: 5,
ease: 5, ease: 5,
@ -89,7 +76,7 @@ function SurveyForm({ theme }) {
}; };
sendMail(); sendMail();
}); });
}, [editor, form, questions]); }, [editor, form]);
return ( return (
<div className="py-5 px-8 mt-6 card-theme rounded-md"> <div className="py-5 px-8 mt-6 card-theme rounded-md">

View File

@ -12,6 +12,7 @@ export default function Templates() {
const defaultTemplates = useLiveQuery(() => const defaultTemplates = useLiveQuery(() =>
db.templates.where({ custom: 0 }).toArray() db.templates.where({ custom: 0 }).toArray()
); );
const customTemplates = useLiveQuery(() => const customTemplates = useLiveQuery(() =>
db.templates.where({ custom: 1 }).toArray() db.templates.where({ custom: 1 }).toArray()
); );
@ -110,7 +111,9 @@ export default function Templates() {
key={i} key={i}
className="bg-gray-100 hover:translate-y-[-6px] transition-all duration-300 border rounded-md" className="bg-gray-100 hover:translate-y-[-6px] transition-all duration-300 border rounded-md"
> >
<Thumbnail diagram={c} i={"2" + i} /> <div className="h-48">
<Thumbnail diagram={c} i={"2" + i} zoom={0.3} />
</div>
<div className="px-4 py-3 w-full"> <div className="px-4 py-3 w-full">
<div className="flex justify-between"> <div className="flex justify-between">
<div className="text-lg font-bold text-zinc-700"> <div className="text-lg font-bold text-zinc-700">