diff --git a/src/components/FollowMode/FollowMode.scss b/src/components/FollowMode/FollowMode.scss index 6cebf2160..383b3ceed 100644 --- a/src/components/FollowMode/FollowMode.scss +++ b/src/components/FollowMode/FollowMode.scss @@ -24,6 +24,7 @@ &__label { display: flex; white-space: pre-wrap; + line-height: 1; } &__username { diff --git a/src/components/UserList.scss b/src/components/UserList.scss index f2720c397..8216d8807 100644 --- a/src/components/UserList.scss +++ b/src/components/UserList.scss @@ -72,6 +72,13 @@ padding: 0.25rem 0.5rem; border-top: 1px solid var(--userlist-collaborators-border-color); border-bottom: 1px solid var(--userlist-collaborators-border-color); + + &__empty { + color: var(--color-gray-60); + font-size: 0.75rem; + line-height: 150%; + padding: 0.5rem 0; + } } .UserList__hint { @@ -94,12 +101,33 @@ } } + .UserList__search-wrapper { + position: relative; + height: 2.5rem; + + svg { + position: absolute; + top: 50%; + transform: translateY(-50%); + left: 0.75rem; + width: 1.25rem; + height: 1.25rem; + color: var(--color-gray-40); + z-index: 1; + } + } + .UserList__search { + position: absolute; + top: 0; + left: 0; width: 100%; box-sizing: border-box; border: 0 !important; border-radius: 0 !important; font-size: 0.875rem; + padding-left: 2.5rem !important; + padding-right: 0.75rem !important; &::placeholder { color: var(--color-gray-40); diff --git a/src/components/UserList.tsx b/src/components/UserList.tsx index a4461d7b1..7ec0d8df6 100644 --- a/src/components/UserList.tsx +++ b/src/components/UserList.tsx @@ -9,7 +9,12 @@ import { ActionManager } from "../actions/manager"; import * as Popover from "@radix-ui/react-popover"; import { Island } from "./Island"; +import { searchIcon } from "./icons"; +import { t } from "../i18n"; +// TODO follow-participant +// can be used for debugging styling, filter, etc +// don't forget to remove it before shipping const sampleCollaborators = new Map([ [ "client-id-1", @@ -70,6 +75,7 @@ const sampleCollaborators = new Map([ ]) as any as Map; const FIRST_N_AVATARS = 3; +const SHOW_COLLABORATORS_FILTER_AT = 6; const ConditionalTooltipWrapper = ({ shouldWrap, @@ -132,16 +138,19 @@ export const UserList = ({ }) => { const actionManager = useExcalidrawActionManager(); - // const uniqueCollaboratorsMap = new Map(); - // collaborators.forEach((collaborator, socketId) => { - // uniqueCollaboratorsMap.set( - // // filter on user id, else fall back on unique socketId - // collaborator.id || socketId, - // collaborator, - // ); - // }); + const uniqueCollaboratorsMap = React.useMemo(() => { + const map = new Map(); + collaborators.forEach((collaborator, socketId) => { + map.set( + // filter on user id, else fall back on unique socketId + collaborator.id || socketId, + collaborator, + ); + }); + return map; + }, [collaborators]); - const uniqueCollaboratorsMap = sampleCollaborators; + // const uniqueCollaboratorsMap = sampleCollaborators; const uniqueCollaboratorsArray = React.useMemo( () => Array.from(uniqueCollaboratorsMap).filter( @@ -210,20 +219,27 @@ export const UserList = ({ sideOffset={10} > - {/* TODO follow-participant add search icon */} -
- { - setSearchTerm(e.target.value); - }} - /> -
+ {SHOW_COLLABORATORS_FILTER_AT <= + uniqueCollaboratorsArray.length && ( +
+ {searchIcon} + { + setSearchTerm(e.target.value); + }} + /> +
+ )}
- {/* TODO follow-participant empty state */} + {filteredCollaborators.length === 0 && ( +
+ {t("userList.search.empty")} +
+ )} {filteredCollaborators.map(([clientId, collaborator]) => renderCollaborator({ actionManager, @@ -233,12 +249,12 @@ export const UserList = ({ }), )}
- {/* TODO follow-participant */}
-
TODO hint
+
+ {t("userList.hint.heading")} +
- Lorem ipsum dolor sit amet consectetur adipisicing elit. - Quibusdam, ipsum! + {t("userList.hint.text")}
diff --git a/src/components/icons.tsx b/src/components/icons.tsx index 1fcaa3c82..ef32da305 100644 --- a/src/components/icons.tsx +++ b/src/components/icons.tsx @@ -1647,3 +1647,12 @@ export const frameToolIcon = createIcon( , tablerIconProps, ); + +export const searchIcon = createIcon( + + + + + , + tablerIconProps, +); diff --git a/src/locales/en.json b/src/locales/en.json index 7092e9be8..7b3d0d127 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -480,5 +480,15 @@ "description": "Loading external drawing will replace your existing content.

You can back up your drawing first by using one of the options below." } } + }, + "userList": { + "search": { + "placeholder": "Quick search", + "empty": "No users found" + }, + "hint": { + "heading": "Follow mode", + "text": "You can click on a user to toggle follow mode. In follow mode, their canvas movements will be mirrored on your canvas." + } } }