MobileMenu.tsx 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. import React from "react";
  2. import { AppState } from "../types";
  3. import { ActionManager } from "../actions/manager";
  4. import { t, setLanguage } from "../i18n";
  5. import Stack from "./Stack";
  6. import { LanguageList } from "./LanguageList";
  7. import { showSelectedShapeActions } from "../element";
  8. import { NonDeletedExcalidrawElement } from "../element/types";
  9. import { FixedSideContainer } from "./FixedSideContainer";
  10. import { Island } from "./Island";
  11. import { HintViewer } from "./HintViewer";
  12. import { calculateScrollCenter } from "../scene";
  13. import { SelectedShapeActions, ShapesSwitcher } from "./Actions";
  14. import { Section } from "./Section";
  15. import { RoomDialog } from "./RoomDialog";
  16. import { SCROLLBAR_WIDTH, SCROLLBAR_MARGIN } from "../scene/scrollbars";
  17. import { LockIcon } from "./LockIcon";
  18. import { LoadingMessage } from "./LoadingMessage";
  19. type MobileMenuProps = {
  20. appState: AppState;
  21. actionManager: ActionManager;
  22. exportButton: React.ReactNode;
  23. setAppState: any;
  24. elements: readonly NonDeletedExcalidrawElement[];
  25. onRoomCreate: () => void;
  26. onUsernameChange: (username: string) => void;
  27. onRoomDestroy: () => void;
  28. onLockToggle: () => void;
  29. };
  30. export function MobileMenu({
  31. appState,
  32. elements,
  33. actionManager,
  34. exportButton,
  35. setAppState,
  36. onRoomCreate,
  37. onUsernameChange,
  38. onRoomDestroy,
  39. onLockToggle,
  40. }: MobileMenuProps) {
  41. return (
  42. <>
  43. {appState.isLoading && <LoadingMessage />}
  44. <FixedSideContainer side="top">
  45. <Section heading="shapes">
  46. {(heading) => (
  47. <Stack.Col gap={4} align="center">
  48. <Stack.Row gap={1}>
  49. <Island padding={1}>
  50. {heading}
  51. <Stack.Row gap={1}>
  52. <ShapesSwitcher
  53. elementType={appState.elementType}
  54. setAppState={setAppState}
  55. />
  56. </Stack.Row>
  57. </Island>
  58. <LockIcon
  59. checked={appState.elementLocked}
  60. onChange={onLockToggle}
  61. title={t("toolBar.lock")}
  62. />
  63. </Stack.Row>
  64. </Stack.Col>
  65. )}
  66. </Section>
  67. <HintViewer appState={appState} elements={elements} />
  68. </FixedSideContainer>
  69. <div
  70. className="App-bottom-bar"
  71. style={{
  72. marginBottom: SCROLLBAR_WIDTH + SCROLLBAR_MARGIN * 2,
  73. marginLeft: SCROLLBAR_WIDTH + SCROLLBAR_MARGIN * 2,
  74. marginRight: SCROLLBAR_WIDTH + SCROLLBAR_MARGIN * 2,
  75. }}
  76. >
  77. <Island padding={3}>
  78. {appState.openMenu === "canvas" ? (
  79. <Section className="App-mobile-menu" heading="canvasActions">
  80. <div className="panelColumn">
  81. <Stack.Col gap={4}>
  82. {actionManager.renderAction("loadScene")}
  83. {actionManager.renderAction("saveScene")}
  84. {exportButton}
  85. {actionManager.renderAction("clearCanvas")}
  86. <RoomDialog
  87. isCollaborating={appState.isCollaborating}
  88. collaboratorCount={appState.collaborators.size}
  89. username={appState.username}
  90. onUsernameChange={onUsernameChange}
  91. onRoomCreate={onRoomCreate}
  92. onRoomDestroy={onRoomDestroy}
  93. />
  94. {actionManager.renderAction("changeViewBackgroundColor")}
  95. <fieldset>
  96. <legend>{t("labels.language")}</legend>
  97. <LanguageList
  98. onChange={(lng) => {
  99. setLanguage(lng);
  100. setAppState({});
  101. }}
  102. />
  103. </fieldset>
  104. </Stack.Col>
  105. </div>
  106. </Section>
  107. ) : appState.openMenu === "shape" &&
  108. showSelectedShapeActions(appState, elements) ? (
  109. <Section className="App-mobile-menu" heading="selectedShapeActions">
  110. <SelectedShapeActions
  111. appState={appState}
  112. elements={elements}
  113. renderAction={actionManager.renderAction}
  114. elementType={appState.elementType}
  115. />
  116. </Section>
  117. ) : null}
  118. <footer className="App-toolbar">
  119. <div className="App-toolbar-content">
  120. {actionManager.renderAction("toggleCanvasMenu")}
  121. {actionManager.renderAction("toggleEditMenu")}
  122. {actionManager.renderAction("undo")}
  123. {actionManager.renderAction("redo")}
  124. {actionManager.renderAction(
  125. appState.multiElement ? "finalize" : "duplicateSelection",
  126. )}
  127. {actionManager.renderAction("deleteSelectedElements")}
  128. </div>
  129. {appState.scrolledOutside && (
  130. <button
  131. className="scroll-back-to-content"
  132. onClick={() => {
  133. setAppState({ ...calculateScrollCenter(elements) });
  134. }}
  135. >
  136. {t("buttons.scrollBackToContent")}
  137. </button>
  138. )}
  139. </footer>
  140. </Island>
  141. </div>
  142. </>
  143. );
  144. }