From 2d36c04a49295f3a2ee863389bbc48822b4bca94 Mon Sep 17 00:00:00 2001 From: 1ilit Date: Tue, 19 Sep 2023 15:50:22 +0300 Subject: [PATCH] keyboard shortcuts baby --- package-lock.json | 10 ++ package.json | 1 + src/components/control_panel.jsx | 171 +++++++++++++++++-------------- 3 files changed, 103 insertions(+), 79 deletions(-) diff --git a/package-lock.json b/package-lock.json index 381cecb..a587bcd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,7 @@ "react-dnd": "^16.0.1", "react-dnd-html5-backend": "^16.0.1", "react-dom": "^18.2.0", + "react-hotkeys-hook": "^4.4.1", "react-router-dom": "^6.11.2", "react-scripts": "5.0.1", "url": "^0.11.1", @@ -15225,6 +15226,15 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", "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": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", diff --git a/package.json b/package.json index 7c72169..9dc159d 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "react-dnd": "^16.0.1", "react-dnd-html5-backend": "^16.0.1", "react-dom": "^18.2.0", + "react-hotkeys-hook": "^4.4.1", "react-router-dom": "^6.11.2", "react-scripts": "5.0.1", "url": "^0.11.1", diff --git a/src/components/control_panel.jsx b/src/components/control_panel.jsx index b3519b7..0852c4b 100644 --- a/src/components/control_panel.jsx +++ b/src/components/control_panel.jsx @@ -49,6 +49,7 @@ import { ObjectType, Action } from "../data/data"; import CodeMirror from "@uiw/react-codemirror"; import { json } from "@codemirror/lang-json"; import jsPDF from "jspdf"; +import { useHotkeys } from "react-hotkeys-hook"; export default function ControlPanel(props) { 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 = { File: { New: { - children: [], - function: () => console.log("New"), + function: () => {}, }, "New window": { - children: [], function: () => {}, }, Save: { - children: [], function: () => {}, }, "Save as": { - children: [], function: () => {}, }, Share: { - children: [], function: () => {}, }, Rename: { - children: [], function: () => {}, }, Import: { - children: [], - function: () => { - setVisible(MODAL.IMPORT); - }, + function: fileImport, + shortcut: "Ctrl+I", }, "Export as": { children: [ @@ -518,183 +547,151 @@ export default function ControlPanel(props) { function: () => {}, }, Properties: { - children: [], function: () => {}, }, Close: { - children: [], function: () => {}, }, }, Edit: { Undo: { - children: [], function: undo, + shortcut: "Ctrl+Z", }, Redo: { - children: [], function: redo, + shortcut: "Ctrl+Y", }, Clear: { - children: [], function: () => { setTables([]); setRelationships([]); setAreas([]); setNotes([]); + setUndoStack([]); + setRedoStack([]); }, }, Edit: { - children: [], function: () => {}, }, Cut: { - children: [], function: () => {}, }, Copy: { - children: [], function: () => {}, }, Paste: { - children: [], function: () => {}, }, Duplicate: { - children: [], function: () => {}, }, Delete: { - children: [], function: () => {}, }, "Copy as image": { - children: [], - function: () => { - 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."); - }); - }); - }, + function: copyAsImage, + shortcut: "Ctrl+Alt+C", }, }, View: { Header: { - children: [], function: () => setLayout((prev) => ({ ...prev, header: !prev.header })), }, Sidebar: { - children: [], function: () => setLayout((prev) => ({ ...prev, sidebar: !prev.sidebar })), }, Issues: { - children: [], function: () => setLayout((prev) => ({ ...prev, issues: !prev.issues })), }, Services: { - children: [], function: () => setLayout((prev) => ({ ...prev, services: !prev.services })), }, "Strict mode": { - children: [], - function: () => { - setSettings((prev) => ({ ...prev, strictMode: !prev.strictMode })); - Toast.success(`Stict mode is ${settings.strictMode ? "on" : "off"}.`); - }, + function: viewStrictMode, + shortcut: "Ctrl+Shift+M", }, "Field summary": { - children: [], - function: () => { - setSettings((prev) => ({ - ...prev, - showFieldSummary: !prev.showFieldSummary, - })); - Toast.success( - `Field summary is ${settings.showFieldSummary ? "off" : "on"}.` - ); - }, + function: viewFieldSummary, + shortcut: "Ctrl+Shift+F", }, "Reset view": { - children: [], - function: () => {}, + function: resetView, + shortcut: "Ctrl+R", }, "View schema": { - children: [], function: () => {}, }, Grid: { - children: [], - function: () => - setSettings((prev) => ({ ...prev, showGrid: !prev.showGrid })), + function: viewGrid, + shortcut: "Ctrl+Shift+G", }, Theme: { children: [{ Light: () => {} }, { Dark: () => {} }], function: () => {}, }, "Zoom in": { - children: [], - function: () => - setSettings((prev) => ({ ...prev, zoom: prev.zoom * 1.2 })), + function: zoomIn, + shortcut: "Ctrl+Up/Wheel", }, "Zoom out": { - children: [], - function: () => - setSettings((prev) => ({ ...prev, zoom: prev.zoom / 1.2 })), + function: zoomOut, + shortcut: "Ctrl+Down/Wheel", }, Fullscreen: { - children: [], function: enterFullscreen, }, }, Logs: { "Open logs": { - children: [], function: () => {}, }, "Commit changes": { - children: [], function: () => {}, }, "Revert changes": { - children: [], function: () => {}, }, "View commits": { - children: [], function: () => {}, }, }, Help: { Shortcuts: { - children: [], function: () => {}, }, "Ask us on discord": { - children: [], function: () => {}, }, "Tweet us": { - children: [], function: () => {}, }, "Found a bug": { - children: [], 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 (
{layout.header && header()} @@ -1040,11 +1037,11 @@ export default function ControlPanel(props) { {Object.keys(menu[category]).map((item, index) => { - if (menu[category][item].children.length > 0) { + if (menu[category][item].children) { return ( - {item} + {menu[category][item].shortcut ? ( + <> +
{item}
+
+ {menu[category][item].shortcut} +
+ + ) : ( + item + )} ); })}