CustomStats.tsx 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. import { useEffect, useState } from "react";
  2. import { debounce, getVersion, nFormatter } from "../packages/excalidraw/utils";
  3. import {
  4. getElementsStorageSize,
  5. getTotalStorageSize,
  6. } from "./data/localStorage";
  7. import { DEFAULT_VERSION } from "../packages/excalidraw/constants";
  8. import { t } from "../packages/excalidraw/i18n";
  9. import { copyTextToSystemClipboard } from "../packages/excalidraw/clipboard";
  10. import { NonDeletedExcalidrawElement } from "../packages/excalidraw/element/types";
  11. import { UIAppState } from "../packages/excalidraw/types";
  12. type StorageSizes = { scene: number; total: number };
  13. const STORAGE_SIZE_TIMEOUT = 500;
  14. const getStorageSizes = debounce((cb: (sizes: StorageSizes) => void) => {
  15. cb({
  16. scene: getElementsStorageSize(),
  17. total: getTotalStorageSize(),
  18. });
  19. }, STORAGE_SIZE_TIMEOUT);
  20. type Props = {
  21. setToast: (message: string) => void;
  22. elements: readonly NonDeletedExcalidrawElement[];
  23. appState: UIAppState;
  24. };
  25. const CustomStats = (props: Props) => {
  26. const [storageSizes, setStorageSizes] = useState<StorageSizes>({
  27. scene: 0,
  28. total: 0,
  29. });
  30. useEffect(() => {
  31. getStorageSizes((sizes) => {
  32. setStorageSizes(sizes);
  33. });
  34. }, [props.elements, props.appState]);
  35. useEffect(() => () => getStorageSizes.cancel(), []);
  36. const version = getVersion();
  37. let hash;
  38. let timestamp;
  39. if (version !== DEFAULT_VERSION) {
  40. timestamp = version.slice(0, 16).replace("T", " ");
  41. hash = version.slice(21);
  42. } else {
  43. timestamp = t("stats.versionNotAvailable");
  44. }
  45. return (
  46. <>
  47. <tr>
  48. <th colSpan={2}>{t("stats.storage")}</th>
  49. </tr>
  50. <tr>
  51. <td>{t("stats.scene")}</td>
  52. <td>{nFormatter(storageSizes.scene, 1)}</td>
  53. </tr>
  54. <tr>
  55. <td>{t("stats.total")}</td>
  56. <td>{nFormatter(storageSizes.total, 1)}</td>
  57. </tr>
  58. <tr>
  59. <th colSpan={2}>{t("stats.version")}</th>
  60. </tr>
  61. <tr>
  62. <td
  63. colSpan={2}
  64. style={{ textAlign: "center", cursor: "pointer" }}
  65. onClick={async () => {
  66. try {
  67. await copyTextToSystemClipboard(getVersion());
  68. props.setToast(t("toast.copyToClipboard"));
  69. } catch {}
  70. }}
  71. title={t("stats.versionCopy")}
  72. >
  73. {timestamp}
  74. <br />
  75. {hash}
  76. </td>
  77. </tr>
  78. </>
  79. );
  80. };
  81. export default CustomStats;