diff --git a/.gitignore b/.gitignore index f21ef9c009cc..48a17db0dfd3 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,6 @@ *.log *.tgz build -dist firebase logs node_modules diff --git a/package.json b/package.json index 2bfb2abdf38d..20110e4b4131 100644 --- a/package.json +++ b/package.json @@ -1,4 +1,8 @@ { + "main": "src/packages/excalidraw/dist/excalidraw.min.js", + "files": [ + "src/packages/excalidraw/dist/*" + ], "browserslist": { "production": [ ">0.2%", @@ -83,6 +87,8 @@ "private": true, "scripts": { "build-node": "node ./scripts/build-node.js", + "build:package": "cd src/packages/excalidraw && npm run build", + "build:package:deploy": "npm run build:package && git add . && git commit -m release --no-edit --no-verify && git push -f && git rev-parse --short HEAD", "build:app:docker": "REACT_APP_DISABLE_SENTRY=true react-scripts build", "build:app": "REACT_APP_GIT_SHA=$VERCEL_GIT_COMMIT_SHA react-scripts build", "build:version": "node ./scripts/build-version.js", diff --git a/src/actions/actionNavigate.tsx b/src/actions/actionNavigate.tsx index 2da47779521a..35067a0ae4da 100644 --- a/src/actions/actionNavigate.tsx +++ b/src/actions/actionNavigate.tsx @@ -42,16 +42,25 @@ export const actionGoToCollaborator = register({ return null; } - const { background, stroke } = getClientColors(clientId, appState); + const { background, stroke } = getClientColors( + clientId || clientId, + appState, + ); + const picture = collaborator.picture; + const shortName = getClientInitials(collaborator.username); return ( updateData(collaborator.pointer)} > - {shortName} + {picture ? ( + {shortName} + ) : ( + shortName + )} ); }, diff --git a/src/components/App.tsx b/src/components/App.tsx index b670ca1a2fa0..86bc561517ce 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -410,15 +410,20 @@ class App extends React.Component { public render() { const { - zenModeEnabled, width: canvasDOMWidth, height: canvasDOMHeight, offsetTop, offsetLeft, viewModeEnabled, + zenModeEnabled, } = this.state; - const { onCollabButtonClick, onExportToBackend, renderFooter } = this.props; + const { + onCollabButtonClick, + onExportToBackend, + renderFooter, + renderTopRight, + } = this.props; const DEFAULT_PASTE_X = canvasDOMWidth / 2; const DEFAULT_PASTE_Y = canvasDOMHeight / 2; @@ -426,6 +431,7 @@ class App extends React.Component { return (
{ isCollaborating={this.props.isCollaborating || false} onExportToBackend={onExportToBackend} renderCustomFooter={renderFooter} + renderTopRight={renderTopRight} viewModeEnabled={viewModeEnabled} showExitZenModeBtn={ typeof this.props?.zenModeEnabled === "undefined" && zenModeEnabled } + onHomeButtonClick={this.props.onHomeButtonClick} />
{this.state.showStats && ( @@ -691,6 +699,13 @@ class App extends React.Component { }; } + if (initialData?.scrollX != null) { + scene.appState.scrollX = initialData.scrollX; + } + if (initialData?.scrollY != null) { + scene.appState.scrollY = initialData.scrollY; + } + this.resetHistory(); this.syncActionResult({ ...scene, @@ -1263,26 +1278,30 @@ class App extends React.Component { this.setState({ toastMessage: null }); }; - public updateScene = withBatchedUpdates((sceneData: SceneData) => { - if (sceneData.commitToHistory) { - history.resumeRecording(); - } + public updateScene = withBatchedUpdates( + (sceneData: { + elements?: SceneData["elements"]; + appState?: Pick; + collaborators?: SceneData["collaborators"]; + commitToHistory?: SceneData["commitToHistory"]; + }) => { + if (sceneData.commitToHistory) { + history.resumeRecording(); + } - // currently we only support syncing background color - if (sceneData.appState?.viewBackgroundColor) { - this.setState({ - viewBackgroundColor: sceneData.appState.viewBackgroundColor, - }); - } + if (sceneData.appState) { + this.setState(sceneData.appState); + } - if (sceneData.elements) { - this.scene.replaceAllElements(sceneData.elements); - } + if (sceneData.elements) { + this.scene.replaceAllElements(sceneData.elements); + } - if (sceneData.collaborators) { - this.setState({ collaborators: sceneData.collaborators }); - } - }); + if (sceneData.collaborators) { + this.setState({ collaborators: sceneData.collaborators }); + } + }, + ); private onSceneUpdated = () => { this.setState({}); diff --git a/src/components/Avatar.scss b/src/components/Avatar.scss index d077d916bf77..e9e542c14409 100644 --- a/src/components/Avatar.scss +++ b/src/components/Avatar.scss @@ -4,7 +4,7 @@ .Avatar { width: 2.5rem; height: 2.5rem; - border-radius: 1.25rem; + border-radius: 50%; display: flex; justify-content: center; align-items: center; @@ -12,5 +12,11 @@ cursor: pointer; font-size: 0.8rem; font-weight: 500; + overflow: hidden; + + img { + width: 100%; + height: 100%; + } } } diff --git a/src/components/Avatar.tsx b/src/components/Avatar.tsx index 2b85137077c5..5b143321b2a3 100644 --- a/src/components/Avatar.tsx +++ b/src/components/Avatar.tsx @@ -3,7 +3,7 @@ import "./Avatar.scss"; import React from "react"; type AvatarProps = { - children: string; + children: JSX.Element | string; onClick: (e: React.MouseEvent) => void; color: string; border: string; @@ -12,7 +12,7 @@ type AvatarProps = { export const Avatar = ({ children, color, border, onClick }: AvatarProps) => (
{children} diff --git a/src/components/BackgroundPickerAndDarkModeToggle.tsx b/src/components/BackgroundPickerAndDarkModeToggle.tsx index f2eba1315a5d..e502b6560183 100644 --- a/src/components/BackgroundPickerAndDarkModeToggle.tsx +++ b/src/components/BackgroundPickerAndDarkModeToggle.tsx @@ -1,7 +1,6 @@ import React from "react"; import { ActionManager } from "../actions/manager"; import { AppState } from "../types"; -import { DarkModeToggle } from "./DarkModeToggle"; export const BackgroundPickerAndDarkModeToggle = ({ appState, @@ -14,13 +13,5 @@ export const BackgroundPickerAndDarkModeToggle = ({ }) => (
{actionManager.renderAction("changeViewBackgroundColor")} -
- { - setAppState({ appearance }); - }} - /> -
); diff --git a/src/components/CollabButton.tsx b/src/components/CollabButton.tsx index f1412f7231e9..eb8d5e8c1f7c 100644 --- a/src/components/CollabButton.tsx +++ b/src/components/CollabButton.tsx @@ -3,7 +3,7 @@ import clsx from "clsx"; import { ToolButton } from "./ToolButton"; import { t } from "../i18n"; import useIsMobile from "../is-mobile"; -import { users } from "./icons"; +import { shareIcon } from "./icons"; import "./CollabButton.scss"; @@ -23,16 +23,12 @@ const CollabButton = ({ "is-collaborating": isCollaborating, })} onClick={onClick} - icon={users} + icon={shareIcon} type="button" title={t("labels.liveCollaboration")} aria-label={t("labels.liveCollaboration")} showAriaLabel={useIsMobile()} - > - {collaboratorCount > 0 && ( -
{collaboratorCount}
- )} - + /> ); }; diff --git a/src/components/ExportDialog.tsx b/src/components/ExportDialog.tsx index cc4219a51696..a25b8b756edf 100644 --- a/src/components/ExportDialog.tsx +++ b/src/components/ExportDialog.tsx @@ -168,10 +168,9 @@ const ExportModal = ({ onClick={() => onExportToBackend(exportedElements)} /> )} + {appState.fileHandle && actionManager.renderAction("saveScene")} + {actionManager.renderAction("saveAsScene")} -
- {actionManager.renderAction("changeProjectName")} -
{scales.map((s) => { const [width, height] = getExportSize( diff --git a/src/components/Island.scss b/src/components/Island.scss index 3fc27c715be0..e2c65e429616 100644 --- a/src/components/Island.scss +++ b/src/components/Island.scss @@ -7,10 +7,49 @@ border-radius: 4px; padding: calc(var(--padding) * var(--space-factor)); position: relative; - transition: box-shadow 0.5s ease-in-out; &.zen-mode { box-shadow: none; } + + &::-webkit-scrollbar { + width: 10px; + } + + &::-webkit-scrollbar-track { + background-color: transparent; + } + + &::-webkit-scrollbar-thumb { + background-color: var(--color-scrollbar-thumb); + } + &::-webkit-scrollbar-thumb:hover { + background-color: var(--color-scrollbar-thumb-hover); + } + + &::-webkit-scrollbar-thumb:active { + background-color: var(--color-scrollbar-thumb-active); + } + } + + .App-menu_top { + .Stack_vertical { + .Island { + min-width: 216px; + } + .Stack_horizontal { + justify-content: center !important; + } + } + } + + &.excalidraw--view-mode { + .App-menu_top { + .Stack_vertical { + .Island { + min-width: auto; + } + } + } } } diff --git a/src/components/LayerUI.scss b/src/components/LayerUI.scss index 60fba5acb0fd..389ce4f207fb 100644 --- a/src/components/LayerUI.scss +++ b/src/components/LayerUI.scss @@ -40,36 +40,6 @@ .layer-ui__wrapper { z-index: var(--zIndex-layerUI); - .encrypted-icon { - position: relative; - margin-inline-start: 15px; - display: flex; - justify-content: center; - align-items: center; - border-radius: var(--space-factor); - color: $oc-green-9; - - svg { - width: 1.2rem; - height: 1.2rem; - } - } - - &__github-corner { - top: 0; - - :root[dir="ltr"] & { - right: 0; - } - - :root[dir="rtl"] & { - left: 0; - } - - position: absolute; - width: 40px; - } - &__footer { position: absolute; z-index: 100; diff --git a/src/components/LayerUI.tsx b/src/components/LayerUI.tsx index 103b0ef846c4..8a606488068c 100644 --- a/src/components/LayerUI.tsx +++ b/src/components/LayerUI.tsx @@ -25,9 +25,8 @@ import CollabButton from "./CollabButton"; import { ErrorDialog } from "./ErrorDialog"; import { ExportCB, ExportDialog } from "./ExportDialog"; import { FixedSideContainer } from "./FixedSideContainer"; -import { GitHubCorner } from "./GitHubCorner"; import { HintViewer } from "./HintViewer"; -import { exportFile, load, shield, trash } from "./icons"; +import { exportFile, load, trash } from "./icons"; import { Island } from "./Island"; import "./LayerUI.scss"; import { LibraryUnit } from "./LibraryUnit"; @@ -61,8 +60,10 @@ interface LayerUIProps { appState: AppState, canvas: HTMLCanvasElement | null, ) => void; + renderTopRight?: (isMobile: boolean) => JSX.Element; renderCustomFooter?: (isMobile: boolean) => JSX.Element; viewModeEnabled: boolean; + onHomeButtonClick?: () => void; } const useOnClickOutside = ( @@ -138,37 +139,37 @@ const LibraryMenuItems = ({ }); }} /> - { - saveLibraryAsJSON() - .catch(muteFSAbortError) - .catch((error) => { - setAppState({ errorMessage: error.message }); - }); - }} - /> - { - if (window.confirm(t("alerts.resetLibrary"))) { - Library.resetLibrary(); - setLibraryItems([]); - } - }} - /> - - - {t("labels.libraries")} - + {library.length > 0 && ( + <> + { + saveLibraryAsJSON() + .catch(muteFSAbortError) + .catch((error) => { + setAppState({ errorMessage: error.message }); + }); + }} + /> + { + if (window.confirm(t("alerts.resetLibrary"))) { + Library.resetLibrary(); + setLibraryItems([]); + } + }} + /> + + )}
, ); @@ -318,25 +319,12 @@ const LayerUI = ({ isCollaborating, onExportToBackend, renderCustomFooter, + renderTopRight, viewModeEnabled, + onHomeButtonClick, }: LayerUIProps) => { const isMobile = useIsMobile(); - const renderEncryptedIcon = () => ( - - - {shield} - - - ); - const renderExportDialog = () => { const createExporter = (type: ExportType): ExportCB => async ( exportedElements, @@ -391,8 +379,6 @@ const LayerUI = ({ - {actionManager.renderAction("saveScene")} - {actionManager.renderAction("saveAsScene")} {renderExportDialog()} @@ -411,12 +397,9 @@ const LayerUI = ({ see https://github.com/excalidraw/excalidraw/pull/1445 */} - + {actionManager.renderAction("loadScene")} - {actionManager.renderAction("saveScene")} - {actionManager.renderAction("saveAsScene")} {renderExportDialog()} - {actionManager.renderAction("clearCanvas")} {onCollabButtonClick && ( )} + {actionManager.renderAction("clearCanvas")} )} +
+ {renderTopRight?.(isMobile)} +
{appState.collaborators.size > 0 && Array.from(appState.collaborators) @@ -572,27 +568,12 @@ const LayerUI = ({ zoom={appState.zoom} />
- {renderEncryptedIcon()}
); }; - const renderGitHubCorner = () => { - return ( - - ); - }; const renderFooter = () => (