Bladeren bron

editing single element

Ryan Di 2 jaren geleden
bovenliggende
commit
3fc89b716a
2 gewijzigde bestanden met toevoegingen van 139 en 69 verwijderingen
  1. 27 2
      src/components/Stats.scss
  2. 112 67
      src/components/Stats.tsx

+ 27 - 2
src/components/Stats.scss

@@ -9,8 +9,33 @@
     z-index: 10;
     pointer-events: all;
 
-    .section {
-      padding: 12px;
+    .sectionContent {
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      justify-content: center;
+    }
+
+    .elementType {
+      font-size: 12px;
+      font-weight: 700;
+      margin-bottom: 8px;
+    }
+
+    .statsItem {
+      margin-bottom: 4px;
+      display: flex;
+      align-items: center;
+      // margin-right: 8px;
+
+      .label {
+        margin-right: 4px;
+        width: 10px;
+      }
+
+      .input {
+        width: 55px;
+      }
     }
 
     h3 {

+ 112 - 67
src/components/Stats.tsx

@@ -1,7 +1,12 @@
 import React from "react";
 import { getCommonBounds } from "../element/bounds";
-import { NonDeletedExcalidrawElement } from "../element/types";
+import { mutateElement } from "../element/mutateElement";
+import {
+  ExcalidrawElement,
+  NonDeletedExcalidrawElement,
+} from "../element/types";
 import { t } from "../i18n";
+import { KEYS } from "../keys";
 import { getTargetElements } from "../scene";
 import { AppState, ExcalidrawProps } from "../types";
 import { CloseIcon } from "./icons";
@@ -19,9 +24,45 @@ export const Stats = (props: {
   const selectedElements = getTargetElements(props.elements, props.appState);
   const selectedBoundingBox = getCommonBounds(selectedElements);
 
+  const stats =
+    selectedElements.length === 1
+      ? [
+          {
+            label: "X",
+            value: Math.round(selectedBoundingBox[0]),
+            element: selectedElements[0],
+            property: "x",
+          },
+          {
+            label: "Y",
+            value: Math.round(selectedBoundingBox[1]),
+            element: selectedElements[0],
+            property: "y",
+          },
+          {
+            label: "W",
+            value: Math.round(selectedBoundingBox[2] - selectedBoundingBox[0]),
+            element: selectedElements[0],
+            property: "width",
+          },
+          {
+            label: "H",
+            value: Math.round(selectedBoundingBox[3] - selectedBoundingBox[1]),
+            element: selectedElements[0],
+            property: "height",
+          },
+          {
+            label: "A",
+            value: selectedElements[0].angle,
+            element: selectedElements[0],
+            property: "angle",
+          },
+        ]
+      : [];
+
   return (
     <div className="Stats">
-      <Island>
+      <Island padding={3}>
         <div className="section">
           <div className="close" onClick={props.onClose}>
             {CloseIcon}
@@ -54,75 +95,79 @@ export const Stats = (props: {
         </div>
 
         {selectedElements.length > 0 && (
-          <>
-            <div className="divider"></div>
+          <div className="section">
+            <h3>{t("stats.elementStats")}</h3>
+
+            <div className="sectionContent">
+              {selectedElements.length === 1 && (
+                <div className="elementType">
+                  {t(`element.${selectedElements[0].type}`)}
+                </div>
+              )}
+
+              <div
+                style={{
+                  display: "grid",
+                  gridTemplateColumns: "repeat(2, 1fr)",
+                  gap: "4px 8px",
+                }}
+              >
+                {stats.map((statsItem) => (
+                  <label
+                    className="color-input-container"
+                    key={statsItem.property}
+                  >
+                    <div
+                      className="color-picker-hash"
+                      style={{
+                        width: "30px",
+                      }}
+                    >
+                      {statsItem.label}
+                    </div>
+                    <input
+                      id={statsItem.label}
+                      defaultValue={statsItem.value}
+                      className="color-picker-input"
+                      style={{
+                        width: "55px",
+                      }}
+                      autoComplete="off"
+                      spellCheck="false"
+                      onKeyDown={(event) => {
+                        const value = Number(event.target.value);
 
-            <div className="section">
-              <h3>{t("stats.elementStats")}</h3>
+                        if (event.key === KEYS.ENTER) {
+                          if (!isNaN(value)) {
+                            mutateElement(statsItem.element, {
+                              [statsItem.property]: value,
+                            });
+                          }
 
-              <table>
-                <tbody>
-                  {selectedElements.length === 1 && (
-                    <tr>
-                      <th colSpan={2}>
-                        {t(`element.${selectedElements[0].type}`)}
-                      </th>
-                    </tr>
-                  )}
+                          event.target.value = statsItem.element[
+                            statsItem.property as keyof ExcalidrawElement
+                          ] as string;
+                        }
+                      }}
+                      onBlur={(event) => {
+                        const value = Number(event.target.value);
 
-                  {selectedElements.length > 1 && (
-                    <>
-                      <tr>
-                        <th colSpan={2}>{t("stats.selected")}</th>
-                      </tr>
-                      <tr>
-                        <td>{t("stats.elements")}</td>
-                        <td>{selectedElements.length}</td>
-                      </tr>
-                    </>
-                  )}
-                  {selectedElements.length > 0 && (
-                    <>
-                      <tr>
-                        <td>{"x"}</td>
-                        <td>{Math.round(selectedBoundingBox[0])}</td>
-                      </tr>
-                      <tr>
-                        <td>{"y"}</td>
-                        <td>{Math.round(selectedBoundingBox[1])}</td>
-                      </tr>
-                      <tr>
-                        <td>{t("stats.width")}</td>
-                        <td>
-                          {Math.round(
-                            selectedBoundingBox[2] - selectedBoundingBox[0],
-                          )}
-                        </td>
-                      </tr>
-                      <tr>
-                        <td>{t("stats.height")}</td>
-                        <td>
-                          {Math.round(
-                            selectedBoundingBox[3] - selectedBoundingBox[1],
-                          )}
-                        </td>
-                      </tr>
-                    </>
-                  )}
-                  {selectedElements.length === 1 && (
-                    <tr>
-                      <td>{t("stats.angle")}</td>
-                      <td>
-                        {`${Math.round(
-                          (selectedElements[0].angle * 180) / Math.PI,
-                        )}°`}
-                      </td>
-                    </tr>
-                  )}
-                </tbody>
-              </table>
+                        if (!isNaN(value)) {
+                          mutateElement(statsItem.element, {
+                            [statsItem.property]: value,
+                          });
+                        }
+
+                        event.target.value = statsItem.element[
+                          statsItem.property as keyof ExcalidrawElement
+                        ] as string;
+                      }}
+                    ></input>
+                  </label>
+                ))}
+              </div>
             </div>
-          </>
+          </div>
         )}
       </Island>
     </div>