feat: support src collaborators (#5114)
* feat: support avatarURLfor collaborators * fix * better avatars :) * use position fixed for tooltips so it renders correctly when offsets updated * update docs * Update src/excalidraw-app/collab/CollabWrapper.tsx * rename avatarUrl to src
This commit is contained in:
parent
22b2e10ddb
commit
9e6d5fdbcb
@ -1,4 +1,4 @@
|
|||||||
import { getClientColors, getClientInitials } from "../clients";
|
import { getClientColors } from "../clients";
|
||||||
import { Avatar } from "../components/Avatar";
|
import { Avatar } from "../components/Avatar";
|
||||||
import { centerScrollOn } from "../scene/scroll";
|
import { centerScrollOn } from "../scene/scroll";
|
||||||
import { Collaborator } from "../types";
|
import { Collaborator } from "../types";
|
||||||
@ -43,16 +43,15 @@ export const actionGoToCollaborator = register({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { background, stroke } = getClientColors(clientId, appState);
|
const { background, stroke } = getClientColors(clientId, appState);
|
||||||
const shortName = getClientInitials(collaborator.username);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Avatar
|
<Avatar
|
||||||
color={background}
|
color={background}
|
||||||
border={stroke}
|
border={stroke}
|
||||||
onClick={() => updateData(collaborator.pointer)}
|
onClick={() => updateData(collaborator.pointer)}
|
||||||
>
|
name={collaborator.username || ""}
|
||||||
{shortName}
|
src={collaborator.src}
|
||||||
</Avatar>
|
/>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -12,5 +12,11 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
|
||||||
|
&-img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,28 @@
|
|||||||
import "./Avatar.scss";
|
import "./Avatar.scss";
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { getClientInitials } from "../clients";
|
||||||
|
|
||||||
type AvatarProps = {
|
type AvatarProps = {
|
||||||
children: string;
|
|
||||||
onClick: (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
|
onClick: (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
|
||||||
color: string;
|
color: string;
|
||||||
border: string;
|
border: string;
|
||||||
|
name: string;
|
||||||
|
src?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Avatar = ({ children, color, border, onClick }: AvatarProps) => (
|
export const Avatar = ({ color, border, onClick, name, src }: AvatarProps) => {
|
||||||
<div
|
const shortName = getClientInitials(name);
|
||||||
className="Avatar"
|
const style = src
|
||||||
style={{ background: color, border: `1px solid ${border}` }}
|
? undefined
|
||||||
onClick={onClick}
|
: { background: color, border: `1px solid ${border}` };
|
||||||
>
|
return (
|
||||||
{children}
|
<div className="Avatar" style={style} onClick={onClick}>
|
||||||
</div>
|
{src ? (
|
||||||
);
|
<img className="Avatar-img" src={src} alt={shortName} />
|
||||||
|
) : (
|
||||||
|
shortName
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
// container in body where the actual tooltip is appended to
|
// container in body where the actual tooltip is appended to
|
||||||
.excalidraw-tooltip {
|
.excalidraw-tooltip {
|
||||||
position: absolute;
|
position: fixed;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
|
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
|
@ -17,6 +17,7 @@ Please add the latest change on the top under the correct section.
|
|||||||
|
|
||||||
#### Features
|
#### Features
|
||||||
|
|
||||||
|
- Support [`src`](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L50) for collaborators. Now onwards host can pass `src` to render the customized avatar for collaborators [#5114](https://github.com/excalidraw/excalidraw/pull/5114).
|
||||||
- Support `libraryItems` argument in `initialData.libraryItems` and `updateScene({ libraryItems })` to be a Promise resolving to `LibraryItems`, and support functional update of `libraryItems` in [`updateScene({ libraryItems })`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#updateScene). [#5101](https://github.com/excalidraw/excalidraw/pull/5101).
|
- Support `libraryItems` argument in `initialData.libraryItems` and `updateScene({ libraryItems })` to be a Promise resolving to `LibraryItems`, and support functional update of `libraryItems` in [`updateScene({ libraryItems })`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#updateScene). [#5101](https://github.com/excalidraw/excalidraw/pull/5101).
|
||||||
- Expose util [`mergeLibraryItems`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#mergeLibraryItems) [#5101](https://github.com/excalidraw/excalidraw/pull/5101).
|
- Expose util [`mergeLibraryItems`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#mergeLibraryItems) [#5101](https://github.com/excalidraw/excalidraw/pull/5101).
|
||||||
- Expose util [`exportToClipboard`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#exportToClipboard) which allows to copy the scene contents to clipboard as `svg`, `png` or `json` [#5103](https://github.com/excalidraw/excalidraw/pull/5103).
|
- Expose util [`exportToClipboard`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#exportToClipboard) which allows to copy the scene contents to clipboard as `svg`, `png` or `json` [#5103](https://github.com/excalidraw/excalidraw/pull/5103).
|
||||||
|
@ -512,7 +512,7 @@ You can use this function to update the scene with the sceneData. It accepts the
|
|||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `elements` | [`ImportedDataState["elements"]`](https://github.com/excalidraw/excalidraw/blob/master/src/data/types.ts#L17) | The `elements` to be updated in the scene |
|
| `elements` | [`ImportedDataState["elements"]`](https://github.com/excalidraw/excalidraw/blob/master/src/data/types.ts#L17) | The `elements` to be updated in the scene |
|
||||||
| `appState` | [`ImportedDataState["appState"]`](https://github.com/excalidraw/excalidraw/blob/master/src/data/types.ts#L18) | The `appState` to be updated in the scene. |
|
| `appState` | [`ImportedDataState["appState"]`](https://github.com/excalidraw/excalidraw/blob/master/src/data/types.ts#L18) | The `appState` to be updated in the scene. |
|
||||||
| `collaborators` | <pre>Map<string, <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L29">Collaborator></a></pre> | The list of collaborators to be updated in the scene. |
|
| `collaborators` | <pre>Map<string, <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L35">Collaborator></a></pre> | The list of collaborators to be updated in the scene. |
|
||||||
| `commitToHistory` | `boolean` | Implies if the `history (undo/redo)` should be recorded. Defaults to `false`. |
|
| `commitToHistory` | `boolean` | Implies if the `history (undo/redo)` should be recorded. Defaults to `false`. |
|
||||||
| `libraryItems` | [LibraryItems](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L200) | Promise<[LibraryItems](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L200)> | ((currentItems: [LibraryItems](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L200)>) => [LibraryItems](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L200) | Promise<[LibraryItems](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L200)>) | The `libraryItems` to be update in the scene. |
|
| `libraryItems` | [LibraryItems](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L200) | Promise<[LibraryItems](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L200)> | ((currentItems: [LibraryItems](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L200)>) => [LibraryItems](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L200) | Promise<[LibraryItems](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L200)>) | The `libraryItems` to be update in the scene. |
|
||||||
|
|
||||||
|
@ -31,7 +31,10 @@ const resolvablePromise = () => {
|
|||||||
|
|
||||||
const renderTopRightUI = () => {
|
const renderTopRightUI = () => {
|
||||||
return (
|
return (
|
||||||
<button onClick={() => alert("This is dummy top right UI")}>
|
<button
|
||||||
|
onClick={() => alert("This is dummy top right UI")}
|
||||||
|
style={{ height: "2.5rem" }}
|
||||||
|
>
|
||||||
{" "}
|
{" "}
|
||||||
Click me{" "}
|
Click me{" "}
|
||||||
</button>
|
</button>
|
||||||
@ -58,6 +61,7 @@ export default function App() {
|
|||||||
const [exportWithDarkMode, setExportWithDarkMode] = useState(false);
|
const [exportWithDarkMode, setExportWithDarkMode] = useState(false);
|
||||||
const [exportEmbedScene, setExportEmbedScene] = useState(false);
|
const [exportEmbedScene, setExportEmbedScene] = useState(false);
|
||||||
const [theme, setTheme] = useState("light");
|
const [theme, setTheme] = useState("light");
|
||||||
|
const [isCollaborating, setIsCollaborating] = useState(false);
|
||||||
|
|
||||||
const initialStatePromiseRef = useRef({ promise: null });
|
const initialStatePromiseRef = useRef({ promise: null });
|
||||||
if (!initialStatePromiseRef.current.promise) {
|
if (!initialStatePromiseRef.current.promise) {
|
||||||
@ -228,6 +232,36 @@ export default function App() {
|
|||||||
/>
|
/>
|
||||||
Switch to Dark Theme
|
Switch to Dark Theme
|
||||||
</label>
|
</label>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={isCollaborating}
|
||||||
|
onChange={() => {
|
||||||
|
if (!isCollaborating) {
|
||||||
|
const collaborators = new Map();
|
||||||
|
collaborators.set("id1", {
|
||||||
|
username: "Doremon",
|
||||||
|
src: "doremon.png",
|
||||||
|
});
|
||||||
|
collaborators.set("id2", {
|
||||||
|
username: "Excalibot",
|
||||||
|
src: "https://avatars.githubusercontent.com/excalibot",
|
||||||
|
});
|
||||||
|
collaborators.set("id3", {
|
||||||
|
username: "Pika",
|
||||||
|
src: "pika.jpeg",
|
||||||
|
});
|
||||||
|
excalidrawRef.current.updateScene({ collaborators });
|
||||||
|
} else {
|
||||||
|
excalidrawRef.current.updateScene({
|
||||||
|
collaborators: new Map(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setIsCollaborating(!isCollaborating);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
Show collaborators
|
||||||
|
</label>
|
||||||
<div>
|
<div>
|
||||||
<button onClick={onCopy.bind(null, "png")}>
|
<button onClick={onCopy.bind(null, "png")}>
|
||||||
Copy to Clipboard as PNG
|
Copy to Clipboard as PNG
|
||||||
|
BIN
src/packages/excalidraw/example/public/doremon.png
Normal file
BIN
src/packages/excalidraw/example/public/doremon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 197 KiB |
BIN
src/packages/excalidraw/example/public/pika.jpeg
Normal file
BIN
src/packages/excalidraw/example/public/pika.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.1 KiB |
@ -45,6 +45,9 @@ export type Collaborator = {
|
|||||||
background: string;
|
background: string;
|
||||||
stroke: string;
|
stroke: string;
|
||||||
};
|
};
|
||||||
|
// The url of the collaborator's avatar, defaults to username intials
|
||||||
|
// if not present
|
||||||
|
src?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type DataURL = string & { _brand: "DataURL" };
|
export type DataURL = string & { _brand: "DataURL" };
|
||||||
|
Loading…
x
Reference in New Issue
Block a user