From b82b0754acdd40e2c539483fdc8e0ebe5a900381 Mon Sep 17 00:00:00 2001 From: David Luzar Date: Wed, 11 Mar 2020 19:42:18 +0100 Subject: [PATCH] Room dialog (#905) * support ToolIcon className and fix label padding * factor some ExportDialog classes out to Modal * initial RoomDialog prototype * change label for another-session button * remove unused css * add color comments * Move the collaboration button to the main menu, add support for mobile * remove button for creating another session * add locks * Fix alignment issue * Reorder button * reuse current scene for collab session * keep collaboration state on restore Co-authored-by: Jed Fox --- src/appState.ts | 3 +- src/components/App.tsx | 38 +++++++- src/components/ExportDialog.css | 25 ----- src/components/ExportDialog.tsx | 4 +- src/components/LayerUI.tsx | 16 +++- src/components/MobileMenu.tsx | 10 ++ src/components/Modal.css | 22 +++++ src/components/RoomDialog.scss | 43 +++++++++ src/components/RoomDialog.tsx | 165 ++++++++++++++++++++++++++++++++ src/components/ToolButton.tsx | 3 +- src/components/ToolIcon.scss | 5 + src/components/icons.tsx | 23 +++++ src/data/index.ts | 2 +- src/locales/en.json | 18 +++- src/styles.scss | 4 - 15 files changed, 341 insertions(+), 40 deletions(-) create mode 100644 src/components/RoomDialog.scss create mode 100644 src/components/RoomDialog.tsx diff --git a/src/appState.ts b/src/appState.ts index c159778f..c54b7acd 100644 --- a/src/appState.ts +++ b/src/appState.ts @@ -1,6 +1,5 @@ import { AppState, FlooredNumber } from "./types"; import { getDateTime } from "./utils"; -import { getCollaborationLinkData } from "./data"; const DEFAULT_PROJECT_NAME = `excalidraw-${getDateTime()}`; export const DEFAULT_FONT = "20px Virgil"; @@ -28,7 +27,7 @@ export function getDefaultAppState(): AppState { cursorY: 0, scrolledOutside: false, name: DEFAULT_PROJECT_NAME, - isCollaborating: !!getCollaborationLinkData(window.location.href), + isCollaborating: false, isResizing: false, selectionElement: null, zoom: 1, diff --git a/src/components/App.tsx b/src/components/App.tsx index c092796e..cb8a41dc 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -190,7 +190,12 @@ export class App extends React.Component { if (commitToHistory) { history.resumeRecording(); } - this.setState({ ...res.appState }); + this.setState(state => ({ + ...res.appState, + isCollaborating: state.isCollaborating, + remotePointers: state.remotePointers, + collaboratorCount: state.collaboratorCount, + })); } }; @@ -226,12 +231,27 @@ export class App extends React.Component { event.preventDefault(); }; + private destroySocketClient = () => { + this.setState({ + isCollaborating: false, + }); + if (this.socket) { + this.socket.close(); + this.socket = null; + this.roomID = null; + this.roomKey = null; + } + }; + private initializeSocketClient = () => { if (this.socket) { return; } const roomMatch = getCollaborationLinkData(window.location.href); if (roomMatch) { + this.setState({ + isCollaborating: true, + }); this.socket = socketIOClient(SOCKET_SERVER); this.roomID = roomMatch[1]; this.roomKey = roomMatch[2]; @@ -611,6 +631,20 @@ export class App extends React.Component { gesture.pointers.delete(event.pointerId); }; + createRoom = async () => { + window.history.pushState( + {}, + "Excalidraw", + await generateCollaborationLink(), + ); + this.initializeSocketClient(); + }; + + destroyRoom = () => { + window.history.pushState({}, "Excalidraw", window.location.origin); + this.destroySocketClient(); + }; + public render() { const canvasDOMWidth = window.innerWidth; const canvasDOMHeight = window.innerHeight; @@ -630,6 +664,8 @@ export class App extends React.Component { elements={elements} setElements={this.setElements} language={getLanguage()} + onRoomCreate={this.createRoom} + onRoomDestroy={this.destroyRoom} />
+
+

{t("labels.createRoom")}

+ {!activeRoomLink && ( + <> +

{t("roomDialog.desc_intro")}

+

{`🔒 ${t("roomDialog.desc_privacy")}`}

+

{t("roomDialog.desc_start")}

+
+ +
+ + )} + {activeRoomLink && ( + <> +

{t("roomDialog.desc_inProgressIntro")}

+

{t("roomDialog.desc_shareLink")}

+
+ + +
+

{`🔒 ${t("roomDialog.desc_privacy")}`}

+

+ {" "} + {t("roomDialog.desc_persistenceWarning")} +

+

{t("roomDialog.desc_exitSession")}

+
+ +
+ + )} +
+
+ ); +} + +export function RoomDialog({ + isCollaborating, + onRoomCreate, + onRoomDestroy, +}: { + isCollaborating: boolean; + onRoomCreate: () => void; + onRoomDestroy: () => void; +}) { + const [modalIsShown, setModalIsShown] = useState(false); + const [activeRoomLink, setActiveRoomLink] = useState(""); + + const triggerButton = useRef(null); + + const handleClose = React.useCallback(() => { + setModalIsShown(false); + triggerButton.current?.focus(); + }, []); + + useEffect(() => { + setActiveRoomLink(isCollaborating ? window.location.href : ""); + }, [isCollaborating]); + + return ( + <> + setModalIsShown(true)} + icon={users} + type="button" + title={t("buttons.roomDialog")} + aria-label={t("buttons.roomDialog")} + showAriaLabel={useIsMobile()} + ref={triggerButton} + /> + {modalIsShown && ( + + + + )} + + ); +} diff --git a/src/components/ToolButton.tsx b/src/components/ToolButton.tsx index e4118495..ea4ea1c6 100644 --- a/src/components/ToolButton.tsx +++ b/src/components/ToolButton.tsx @@ -17,6 +17,7 @@ type ToolButtonBaseProps = { showAriaLabel?: boolean; visible?: boolean; selected?: boolean; + className?: string; }; type ToolButtonProps = @@ -43,7 +44,7 @@ export const ToolButton = React.forwardRef(function(