keyboard shortcuts baby

This commit is contained in:
1ilit 2023-09-19 15:50:22 +03:00
parent 850a4b68cf
commit 2d36c04a49
3 changed files with 103 additions and 79 deletions

10
package-lock.json generated
View File

@ -27,6 +27,7 @@
"react-dnd": "^16.0.1", "react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^16.0.1", "react-dnd-html5-backend": "^16.0.1",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-hotkeys-hook": "^4.4.1",
"react-router-dom": "^6.11.2", "react-router-dom": "^6.11.2",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"url": "^0.11.1", "url": "^0.11.1",
@ -15225,6 +15226,15 @@
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz",
"integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg=="
}, },
"node_modules/react-hotkeys-hook": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/react-hotkeys-hook/-/react-hotkeys-hook-4.4.1.tgz",
"integrity": "sha512-sClBMBioFEgFGYLTWWRKvhxcCx1DRznd+wkFHwQZspnRBkHTgruKIHptlK/U/2DPX8BhHoRGzpMVWUXMmdZlmw==",
"peerDependencies": {
"react": ">=16.8.1",
"react-dom": ">=16.8.1"
}
},
"node_modules/react-is": { "node_modules/react-is": {
"version": "17.0.2", "version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",

View File

@ -22,6 +22,7 @@
"react-dnd": "^16.0.1", "react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^16.0.1", "react-dnd-html5-backend": "^16.0.1",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-hotkeys-hook": "^4.4.1",
"react-router-dom": "^6.11.2", "react-router-dom": "^6.11.2",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"url": "^0.11.1", "url": "^0.11.1",

View File

@ -49,6 +49,7 @@ import { ObjectType, Action } from "../data/data";
import CodeMirror from "@uiw/react-codemirror"; import CodeMirror from "@uiw/react-codemirror";
import { json } from "@codemirror/lang-json"; import { json } from "@codemirror/lang-json";
import jsPDF from "jspdf"; import jsPDF from "jspdf";
import { useHotkeys } from "react-hotkeys-hook";
export default function ControlPanel(props) { export default function ControlPanel(props) {
const MODAL = { const MODAL = {
@ -368,37 +369,65 @@ export default function ControlPanel(props) {
} }
}; };
const fileImport = () => setVisible(MODAL.IMPORT);
const viewGrid = () =>
setSettings((prev) => ({ ...prev, showGrid: !prev.showGrid }));
const zoomIn = () =>
setSettings((prev) => ({ ...prev, zoom: prev.zoom * 1.2 }));
const zoomOut = () =>
setSettings((prev) => ({ ...prev, zoom: prev.zoom / 1.2 }));
const viewStrictMode = () => {
setSettings((prev) => ({ ...prev, strictMode: !prev.strictMode }));
Toast.success(`Stict mode is ${settings.strictMode ? "on" : "off"}.`);
};
const viewFieldSummary = () => {
setSettings((prev) => ({
...prev,
showFieldSummary: !prev.showFieldSummary,
}));
Toast.success(
`Field summary is ${settings.showFieldSummary ? "off" : "on"}.`
);
};
const copyAsImage = () => {
toPng(document.getElementById("canvas")).then(function (dataUrl) {
const blob = dataURItoBlob(dataUrl);
navigator.clipboard
.write([new ClipboardItem({ "image/png": blob })])
.then(() => {
Toast.success("Copied to clipboard.");
})
.catch((e) => {
Toast.error("Could not copy to clipboard.");
});
});
};
const resetView = () =>
setSettings((prev) => ({ ...prev, zoom: 1, pan: { x: 0, y: 0 } }));
const menu = { const menu = {
File: { File: {
New: { New: {
children: [], function: () => {},
function: () => console.log("New"),
}, },
"New window": { "New window": {
children: [],
function: () => {}, function: () => {},
}, },
Save: { Save: {
children: [],
function: () => {}, function: () => {},
}, },
"Save as": { "Save as": {
children: [],
function: () => {}, function: () => {},
}, },
Share: { Share: {
children: [],
function: () => {}, function: () => {},
}, },
Rename: { Rename: {
children: [],
function: () => {}, function: () => {},
}, },
Import: { Import: {
children: [], function: fileImport,
function: () => { shortcut: "Ctrl+I",
setVisible(MODAL.IMPORT);
},
}, },
"Export as": { "Export as": {
children: [ children: [
@ -518,183 +547,151 @@ export default function ControlPanel(props) {
function: () => {}, function: () => {},
}, },
Properties: { Properties: {
children: [],
function: () => {}, function: () => {},
}, },
Close: { Close: {
children: [],
function: () => {}, function: () => {},
}, },
}, },
Edit: { Edit: {
Undo: { Undo: {
children: [],
function: undo, function: undo,
shortcut: "Ctrl+Z",
}, },
Redo: { Redo: {
children: [],
function: redo, function: redo,
shortcut: "Ctrl+Y",
}, },
Clear: { Clear: {
children: [],
function: () => { function: () => {
setTables([]); setTables([]);
setRelationships([]); setRelationships([]);
setAreas([]); setAreas([]);
setNotes([]); setNotes([]);
setUndoStack([]);
setRedoStack([]);
}, },
}, },
Edit: { Edit: {
children: [],
function: () => {}, function: () => {},
}, },
Cut: { Cut: {
children: [],
function: () => {}, function: () => {},
}, },
Copy: { Copy: {
children: [],
function: () => {}, function: () => {},
}, },
Paste: { Paste: {
children: [],
function: () => {}, function: () => {},
}, },
Duplicate: { Duplicate: {
children: [],
function: () => {}, function: () => {},
}, },
Delete: { Delete: {
children: [],
function: () => {}, function: () => {},
}, },
"Copy as image": { "Copy as image": {
children: [], function: copyAsImage,
function: () => { shortcut: "Ctrl+Alt+C",
toPng(document.getElementById("canvas")).then(function (dataUrl) {
const blob = dataURItoBlob(dataUrl);
navigator.clipboard
.write([new ClipboardItem({ "image/png": blob })])
.then(() => {
Toast.success("Copied to clipboard.");
})
.catch((error) => {
Toast.error("Could not copy to clipboard.");
});
});
},
}, },
}, },
View: { View: {
Header: { Header: {
children: [],
function: () => function: () =>
setLayout((prev) => ({ ...prev, header: !prev.header })), setLayout((prev) => ({ ...prev, header: !prev.header })),
}, },
Sidebar: { Sidebar: {
children: [],
function: () => function: () =>
setLayout((prev) => ({ ...prev, sidebar: !prev.sidebar })), setLayout((prev) => ({ ...prev, sidebar: !prev.sidebar })),
}, },
Issues: { Issues: {
children: [],
function: () => function: () =>
setLayout((prev) => ({ ...prev, issues: !prev.issues })), setLayout((prev) => ({ ...prev, issues: !prev.issues })),
}, },
Services: { Services: {
children: [],
function: () => function: () =>
setLayout((prev) => ({ ...prev, services: !prev.services })), setLayout((prev) => ({ ...prev, services: !prev.services })),
}, },
"Strict mode": { "Strict mode": {
children: [], function: viewStrictMode,
function: () => { shortcut: "Ctrl+Shift+M",
setSettings((prev) => ({ ...prev, strictMode: !prev.strictMode }));
Toast.success(`Stict mode is ${settings.strictMode ? "on" : "off"}.`);
},
}, },
"Field summary": { "Field summary": {
children: [], function: viewFieldSummary,
function: () => { shortcut: "Ctrl+Shift+F",
setSettings((prev) => ({
...prev,
showFieldSummary: !prev.showFieldSummary,
}));
Toast.success(
`Field summary is ${settings.showFieldSummary ? "off" : "on"}.`
);
},
}, },
"Reset view": { "Reset view": {
children: [], function: resetView,
function: () => {}, shortcut: "Ctrl+R",
}, },
"View schema": { "View schema": {
children: [],
function: () => {}, function: () => {},
}, },
Grid: { Grid: {
children: [], function: viewGrid,
function: () => shortcut: "Ctrl+Shift+G",
setSettings((prev) => ({ ...prev, showGrid: !prev.showGrid })),
}, },
Theme: { Theme: {
children: [{ Light: () => {} }, { Dark: () => {} }], children: [{ Light: () => {} }, { Dark: () => {} }],
function: () => {}, function: () => {},
}, },
"Zoom in": { "Zoom in": {
children: [], function: zoomIn,
function: () => shortcut: "Ctrl+Up/Wheel",
setSettings((prev) => ({ ...prev, zoom: prev.zoom * 1.2 })),
}, },
"Zoom out": { "Zoom out": {
children: [], function: zoomOut,
function: () => shortcut: "Ctrl+Down/Wheel",
setSettings((prev) => ({ ...prev, zoom: prev.zoom / 1.2 })),
}, },
Fullscreen: { Fullscreen: {
children: [],
function: enterFullscreen, function: enterFullscreen,
}, },
}, },
Logs: { Logs: {
"Open logs": { "Open logs": {
children: [],
function: () => {}, function: () => {},
}, },
"Commit changes": { "Commit changes": {
children: [],
function: () => {}, function: () => {},
}, },
"Revert changes": { "Revert changes": {
children: [],
function: () => {}, function: () => {},
}, },
"View commits": { "View commits": {
children: [],
function: () => {}, function: () => {},
}, },
}, },
Help: { Help: {
Shortcuts: { Shortcuts: {
children: [],
function: () => {}, function: () => {},
}, },
"Ask us on discord": { "Ask us on discord": {
children: [],
function: () => {}, function: () => {},
}, },
"Tweet us": { "Tweet us": {
children: [],
function: () => {}, function: () => {},
}, },
"Found a bug": { "Found a bug": {
children: [],
function: () => {}, function: () => {},
}, },
}, },
}; };
useHotkeys("ctrl+i, meta+i", fileImport, { preventDefault: true });
useHotkeys("ctrl+z, meta+z", undo, { preventDefault: true });
useHotkeys("ctrl+y, meta+y", redo, { preventDefault: true });
useHotkeys("ctrl+shift+g, meta+shift+g", viewGrid, { preventDefault: true });
useHotkeys("ctrl+up, meta+up", zoomIn, { preventDefault: true });
useHotkeys("ctrl+down, meta+down", zoomOut, { preventDefault: true });
useHotkeys("ctrl+shift+m, meta+shift+m", viewStrictMode, {
preventDefault: true,
});
useHotkeys("ctrl+shift+f, meta+shift+f", viewFieldSummary, {
preventDefault: true,
});
useHotkeys("ctrl+alt+c, meta+alt+c", copyAsImage, { preventDefault: true });
useHotkeys("ctrl+r, meta+r", resetView, { preventDefault: true });
return ( return (
<div> <div>
{layout.header && header()} {layout.header && header()}
@ -1040,11 +1037,11 @@ export default function ControlPanel(props) {
<Dropdown <Dropdown
key={category} key={category}
position="bottomLeft" position="bottomLeft"
style={{ width: "200px" }} style={{ width: "220px" }}
render={ render={
<Dropdown.Menu> <Dropdown.Menu>
{Object.keys(menu[category]).map((item, index) => { {Object.keys(menu[category]).map((item, index) => {
if (menu[category][item].children.length > 0) { if (menu[category][item].children) {
return ( return (
<Dropdown <Dropdown
style={{ width: "120px" }} style={{ width: "120px" }}
@ -1083,8 +1080,24 @@ export default function ControlPanel(props) {
<Dropdown.Item <Dropdown.Item
key={index} key={index}
onClick={menu[category][item].function} onClick={menu[category][item].function}
style={
menu[category][item].shortcut && {
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}
}
> >
{item} {menu[category][item].shortcut ? (
<>
<div>{item}</div>
<div className="text-gray-400">
{menu[category][item].shortcut}
</div>
</>
) : (
item
)}
</Dropdown.Item> </Dropdown.Item>
); );
})} })}