浏览代码

Add duplicate button for mobile view (#1146)

* Add a icon for dulplication

* Add PanelComponent for duplication

* Add duplicate button for mobile

* Add styles for layout action buttons

* Add a translation for 'Actions'

* Show left action buttons only for desktop

* Add duplicate button at the bottom of mobile

It is provided depending on whether or not it is `multiElement` to maintain space between buttons.
Sanghyeon Lee 5 年之前
父节点
当前提交
86d0da5204

+ 18 - 0
src/actions/actionDuplicateSelection.ts → src/actions/actionDuplicateSelection.tsx

@@ -1,7 +1,13 @@
+import React from "react";
 import { KEYS } from "../keys";
 import { register } from "./register";
 import { ExcalidrawElement } from "../element/types";
 import { duplicateElement } from "../element";
+import { isSomeElementSelected } from "../scene";
+import { ToolButton } from "../components/ToolButton";
+import { clone } from "../components/icons";
+import { t } from "../i18n";
+import { getShortcutKey } from "../utils";
 
 export const actionDuplicateSelection = register({
   name: "duplicateSelection",
@@ -28,4 +34,16 @@ export const actionDuplicateSelection = register({
   },
   contextItemLabel: "labels.duplicateSelection",
   keyTest: (event) => event[KEYS.CTRL_OR_CMD] && event.key === "d",
+  PanelComponent: ({ elements, appState, updateData }) => (
+    <ToolButton
+      type="button"
+      icon={clone}
+      title={`${t("labels.duplicateSelection")} ${getShortcutKey(
+        "CtrlOrCmd+D",
+      )}`}
+      aria-label={t("labels.duplicateSelection")}
+      onClick={() => updateData(null)}
+      visible={isSomeElementSelected(elements, appState)}
+    />
+  ),
 });

+ 12 - 6
src/components/Actions.tsx

@@ -8,6 +8,7 @@ import { ToolButton } from "./ToolButton";
 import { capitalizeString, getShortcutKey } from "../utils";
 import { CURSOR_TYPE } from "../constants";
 import Stack from "./Stack";
+import useIsMobile from "../is-mobile";
 
 export function SelectedShapeActions({
   targetElements,
@@ -18,6 +19,8 @@ export function SelectedShapeActions({
   renderAction: ActionManager["renderAction"];
   elementType: ExcalidrawElement["type"];
 }) {
+  const isMobile = useIsMobile();
+
   return (
     <div className="panelColumn">
       {renderAction("changeStrokeColor")}
@@ -59,12 +62,15 @@ export function SelectedShapeActions({
           {renderAction("bringForward")}
         </div>
       </fieldset>
-      <fieldset>
-        <legend>Layers Actions</legend>
-        <div className="buttonList">
-          {renderAction("deleteSelectedElements")}
-        </div>
-      </fieldset>
+      {!isMobile && (
+        <fieldset>
+          <legend>{t("labels.actions")}</legend>
+          <div className="buttonList">
+            {renderAction("duplicateSelection")}
+            {renderAction("deleteSelectedElements")}
+          </div>
+        </fieldset>
+      )}
     </div>
   );
 }

+ 3 - 1
src/components/MobileMenu.tsx

@@ -122,7 +122,9 @@ export function MobileMenu({
               {actionManager.renderAction("toggleEditMenu")}
               {actionManager.renderAction("undo")}
               {actionManager.renderAction("redo")}
-              {actionManager.renderAction("finalize")}
+              {actionManager.renderAction(
+                appState.multiElement ? "finalize" : "duplicateSelection",
+              )}
               {actionManager.renderAction("deleteSelectedElements")}
             </div>
             {appState.scrolledOutside && (

+ 6 - 0
src/components/icons.tsx

@@ -210,3 +210,9 @@ export const back = createIcon(
   512,
   { marginLeft: "-0.2rem" },
 );
+
+export const clone = createIcon(
+  "M464 0c26.51 0 48 21.49 48 48v288c0 26.51-21.49 48-48 48H176c-26.51 0-48-21.49-48-48V48c0-26.51 21.49-48 48-48h288M176 416c-44.112 0-80-35.888-80-80V128H48c-26.51 0-48 21.49-48 48v288c0 26.51 21.49 48 48 48h288c26.51 0 48-21.49 48-48v-48H176z",
+  512,
+  512,
+);

+ 1 - 0
src/locales/en.json

@@ -42,6 +42,7 @@
     "canvasBackground": "Canvas background",
     "drawingCanvas": "Drawing Canvas",
     "layers": "Layers",
+    "actions": "Actions",
     "language": "Language",
     "createRoom": "Share a live-collaboration session",
     "duplicateSelection": "Duplicate selected elements"

+ 9 - 0
src/styles.scss

@@ -92,6 +92,15 @@ canvas {
       position: absolute;
       pointer-events: none;
     }
+
+    .ToolIcon {
+      margin: 0 5px;
+    }
+
+    .ToolIcon__icon {
+      width: 28px;
+      height: 28px;
+    }
   }
 
   fieldset {