diff --git a/src/actions/actionCanvas.tsx b/src/actions/actionCanvas.tsx index a819a17b..96e03c67 100644 --- a/src/actions/actionCanvas.tsx +++ b/src/actions/actionCanvas.tsx @@ -10,6 +10,7 @@ import { getShortcutKey } from "../utils"; import useIsMobile from "../is-mobile"; import { register } from "./register"; import { newElementWith } from "../element/mutateElement"; +import { AppState } from "../types"; export const actionChangeViewBackgroundColor = register({ name: "changeViewBackgroundColor", @@ -35,12 +36,15 @@ export const actionChangeViewBackgroundColor = register({ export const actionClearCanvas = register({ name: "clearCanvas", - perform: (elements) => { + perform: (elements, appState: AppState) => { return { elements: elements.map((element) => newElementWith(element, { isDeleted: true }), ), - appState: getDefaultAppState(), + appState: { + ...getDefaultAppState(), + username: appState.username, + }, commitToHistory: true, }; }, diff --git a/src/appState.ts b/src/appState.ts index 390a63f1..ddf4526a 100644 --- a/src/appState.ts +++ b/src/appState.ts @@ -29,6 +29,7 @@ export function getDefaultAppState(): AppState { cursorButton: "up", scrolledOutside: false, name: `excalidraw-${getDateTime()}`, + username: "", isCollaborating: false, isResizing: false, isRotating: false, diff --git a/src/components/App.tsx b/src/components/App.tsx index 2b91a74b..0db80894 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -437,6 +437,7 @@ export class App extends React.Component { } = {}; const pointerViewportCoords: SceneState["remotePointerViewportCoords"] = {}; const remoteSelectedElementIds: SceneState["remoteSelectedElementIds"] = {}; + const pointerUsernames: { [id: string]: string } = {}; this.state.collaborators.forEach((user, socketID) => { if (user.selectedElementIds) { for (const id of Object.keys(user.selectedElementIds)) { @@ -449,6 +450,9 @@ export class App extends React.Component { if (!user.pointer) { return; } + if (user.username) { + pointerUsernames[socketID] = user.username; + } pointerViewportCoords[socketID] = sceneCoordsToViewportCoords( { sceneX: user.pointer.x, @@ -483,6 +487,7 @@ export class App extends React.Component { remotePointerViewportCoords: pointerViewportCoords, remotePointerButton: cursorButton, remoteSelectedElementIds: remoteSelectedElementIds, + remotePointerUsernames: pointerUsernames, shouldCacheIgnoreZoom: this.state.shouldCacheIgnoreZoom, }, { @@ -884,6 +889,7 @@ export class App extends React.Component { socketID, pointerCoords, button, + username, selectedElementIds, } = decryptedData.payload; this.setState((state) => { @@ -894,6 +900,7 @@ export class App extends React.Component { user.pointer = pointerCoords; user.button = button; user.selectedElementIds = selectedElementIds; + user.username = username; state.collaborators.set(socketID, user); return state; }); @@ -947,6 +954,7 @@ export class App extends React.Component { pointerCoords: payload.pointerCoords, button: payload.button || "up", selectedElementIds: this.state.selectedElementIds, + username: this.state.username, }, }; return this._broadcastSocketData( diff --git a/src/components/LayerUI.tsx b/src/components/LayerUI.tsx index 41e689f0..fe746e45 100644 --- a/src/components/LayerUI.tsx +++ b/src/components/LayerUI.tsx @@ -133,6 +133,12 @@ export const LayerUI = React.memo( { + setAppState({ + username, + }); + }} onRoomCreate={onRoomCreate} onRoomDestroy={onRoomDestroy} /> diff --git a/src/components/MobileMenu.tsx b/src/components/MobileMenu.tsx index 4d85adda..148d3ad1 100644 --- a/src/components/MobileMenu.tsx +++ b/src/components/MobileMenu.tsx @@ -90,6 +90,8 @@ export function MobileMenu({ setAppState({ username })} onRoomCreate={onRoomCreate} onRoomDestroy={onRoomDestroy} /> diff --git a/src/components/RoomDialog.scss b/src/components/RoomDialog.scss index 54cfdc89..61c379da 100644 --- a/src/components/RoomDialog.scss +++ b/src/components/RoomDialog.scss @@ -36,6 +36,33 @@ background-color: #eee; } +.RoomDialog-usernameContainer { + display: flex; + margin: 1.5em 0; + display: flex; + align-items: center; + justify-content: center; +} + +.RoomDialog-usernameLabel { +} + +.RoomDialog-username { + min-width: 0; + flex: 1 1 auto; + margin-left: 1em; + display: inline-block; + cursor: pointer; + border: none; + height: 2.5rem; + line-height: 2.5rem; + padding: 0 0.5rem; + white-space: nowrap; + border-radius: var(--space-factor); + background-color: #fff; + border: 1px solid #eee; +} + .RoomDialog-link:hover { background-color: #eee; } diff --git a/src/components/RoomDialog.tsx b/src/components/RoomDialog.tsx index 8da9863f..d80a241b 100644 --- a/src/components/RoomDialog.tsx +++ b/src/components/RoomDialog.tsx @@ -11,14 +11,19 @@ import { AppState } from "../types"; function RoomModal({ activeRoomLink, + username, + onUsernameChange, onRoomCreate, onRoomDestroy, }: { activeRoomLink: string; + username: string; + onUsernameChange: (username: string) => void; onRoomCreate: () => void; onRoomDestroy: () => void; }) { const roomLinkInput = useRef(null); + function copyRoomLink() { copyTextToSystemClipboard(activeRoomLink); if (roomLinkInput.current) { @@ -71,6 +76,17 @@ function RoomModal({ onPointerDown={selectInput} /> +
+ + onUsernameChange(event.target.value)} + /> +

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