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 12c2fb9918f6..6ed6a6c81512 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%", @@ -84,6 +88,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/actionExport.tsx b/src/actions/actionExport.tsx index cf303f79b324..1a46aebe0668 100644 --- a/src/actions/actionExport.tsx +++ b/src/actions/actionExport.tsx @@ -63,11 +63,7 @@ export const actionChangeExportEmbedScene = register({ onChange={(event) => updateData(event.target.checked)} />{" "} {t("labels.exportEmbedScene")} - +
{questionCircle}
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 95e577778b26..a09670e97493 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -411,13 +411,18 @@ class App extends React.Component { public render() { const { - zenModeEnabled, width: canvasDOMWidth, height: canvasDOMHeight, 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; @@ -425,6 +430,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 && ( @@ -692,6 +700,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, @@ -1277,26 +1292,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..ba579655c76a 100644 --- a/src/components/CollabButton.tsx +++ b/src/components/CollabButton.tsx @@ -28,11 +28,7 @@ const CollabButton = ({ 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 6bcaac7ece81..40c76109fdfc 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"; @@ -39,7 +38,6 @@ import { Section } from "./Section"; import { HelpDialog } from "./HelpDialog"; import Stack from "./Stack"; import { ToolButton } from "./ToolButton"; -import { Tooltip } from "./Tooltip"; import { UserList } from "./UserList"; interface LayerUIProps { @@ -61,8 +59,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 +138,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 +318,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 +378,6 @@ const LayerUI = ({ - {actionManager.renderAction("saveScene")} - {actionManager.renderAction("saveAsScene")} {renderExportDialog()} @@ -411,12 +396,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 && ( )} +
+ {renderTopRight?.(isMobile)} +
- {appState.collaborators.size > 0 && - Array.from(appState.collaborators) - // Collaborator is either not initialized or is actually the current user. - .filter(([_, client]) => Object.keys(client).length !== 0) - .map(([clientId, client]) => ( - - {actionManager.renderAction("goToCollaborator", clientId)} - - ))} - + layout="vertical" + collaborators={appState.collaborators} + actionManager={actionManager} + />
); @@ -573,27 +555,12 @@ const LayerUI = ({ zoom={appState.zoom} /> - {renderEncryptedIcon()}
); }; - const renderGitHubCorner = () => { - return ( - - ); - }; const renderFooter = () => (