Merge pull request #5898 from matrix-org/t3chguy/fix/16976

Iterate the spaces face pile design
This commit is contained in:
Michael Telatynski 2021-04-22 09:29:00 +01:00 committed by GitHub
commit d9dac7b261
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 71 additions and 45 deletions

View file

@ -224,35 +224,6 @@ $SpaceRoomViewInnerWidth: 428px;
.mx_FacePile_faces { .mx_FacePile_faces {
cursor: pointer; cursor: pointer;
> span:hover {
.mx_BaseAvatar {
filter: brightness(0.8);
}
}
> span:first-child {
position: relative;
.mx_BaseAvatar {
filter: brightness(0.8);
}
&::before {
content: "";
z-index: 1;
position: absolute;
top: 0;
left: 0;
height: 30px;
width: 30px;
background: #ffffff; // white icon fill
mask-position: center;
mask-size: 24px;
mask-repeat: no-repeat;
mask-image: url('$(res)/img/element-icons/room/ellipsis.svg');
}
}
} }
} }

View file

@ -20,7 +20,7 @@ limitations under the License.
flex-direction: row-reverse; flex-direction: row-reverse;
vertical-align: middle; vertical-align: middle;
> span + span { > .mx_FacePile_face + .mx_FacePile_face {
margin-right: -8px; margin-right: -8px;
} }
@ -31,9 +31,32 @@ limitations under the License.
.mx_BaseAvatar_initial { .mx_BaseAvatar_initial {
margin: 1px; // to offset the border on the image margin: 1px; // to offset the border on the image
} }
.mx_FacePile_more {
position: relative;
border-radius: 100%;
width: 30px;
height: 30px;
background-color: $groupFilterPanel-bg-color;
&::before {
content: "";
z-index: 1;
position: absolute;
top: 0;
left: 0;
height: inherit;
width: inherit;
background: $tertiary-fg-color;
mask-position: center;
mask-size: 20px;
mask-repeat: no-repeat;
mask-image: url('$(res)/img/element-icons/room/ellipsis.svg');
}
}
} }
> span { .mx_FacePile_summary {
margin-left: 12px; margin-left: 12px;
font-size: $font-14px; font-size: $font-14px;
line-height: $font-24px; line-height: $font-24px;

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import React, { HTMLAttributes } from "react"; import React, { HTMLAttributes, ReactNode, useContext } from "react";
import { Room } from "matrix-js-sdk/src/models/room"; import { Room } from "matrix-js-sdk/src/models/room";
import { RoomMember } from "matrix-js-sdk/src/models/room-member"; import { RoomMember } from "matrix-js-sdk/src/models/room-member";
import { sortBy } from "lodash"; import { sortBy } from "lodash";
@ -24,6 +24,7 @@ import { _t } from "../../../languageHandler";
import DMRoomMap from "../../../utils/DMRoomMap"; import DMRoomMap from "../../../utils/DMRoomMap";
import TextWithTooltip from "../elements/TextWithTooltip"; import TextWithTooltip from "../elements/TextWithTooltip";
import { useRoomMembers } from "../../../hooks/useRoomMembers"; import { useRoomMembers } from "../../../hooks/useRoomMembers";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
const DEFAULT_NUM_FACES = 5; const DEFAULT_NUM_FACES = 5;
@ -36,6 +37,7 @@ interface IProps extends HTMLAttributes<HTMLSpanElement> {
const isKnownMember = (member: RoomMember) => !!DMRoomMap.shared().getDMRoomsForUserId(member.userId)?.length; const isKnownMember = (member: RoomMember) => !!DMRoomMap.shared().getDMRoomsForUserId(member.userId)?.length;
const FacePile = ({ room, onlyKnownUsers = true, numShown = DEFAULT_NUM_FACES, ...props }: IProps) => { const FacePile = ({ room, onlyKnownUsers = true, numShown = DEFAULT_NUM_FACES, ...props }: IProps) => {
const cli = useContext(MatrixClientContext);
let members = useRoomMembers(room); let members = useRoomMembers(room);
// sort users with an explicit avatar first // sort users with an explicit avatar first
@ -46,21 +48,42 @@ const FacePile = ({ room, onlyKnownUsers = true, numShown = DEFAULT_NUM_FACES, .
// sort known users first // sort known users first
iteratees.unshift(member => isKnownMember(member)); iteratees.unshift(member => isKnownMember(member));
} }
if (members.length < 1) return null;
const shownMembers = sortBy(members, iteratees).slice(0, numShown); // exclude ourselves from the shown members list
const shownMembers = sortBy(members.filter(m => m.userId !== cli.getUserId()), iteratees).slice(0, numShown);
if (shownMembers.length < 1) return null;
// We reverse the order of the shown faces in CSS to simplify their visual overlap,
// reverse members in tooltip order to make the order between the two match up.
const commaSeparatedMembers = shownMembers.map(m => m.rawDisplayName).reverse().join(", ");
let tooltip: ReactNode;
if (props.onClick) {
tooltip = <div>
<div className="mx_Tooltip_title">
{ _t("View all %(count)s members", { count: members.length }) }
</div>
<div className="mx_Tooltip_sub">
{ _t("Including %(commaSeparatedMembers)s", { commaSeparatedMembers }) }
</div>
</div>;
} else {
tooltip = _t("%(count)s members including %(commaSeparatedMembers)s", {
count: members.length,
commaSeparatedMembers,
});
}
return <div {...props} className="mx_FacePile"> return <div {...props} className="mx_FacePile">
<div className="mx_FacePile_faces"> <TextWithTooltip class="mx_FacePile_faces" tooltip={tooltip} tooltipProps={{ yOffset: 32 }}>
{ shownMembers.map(member => { { members.length > numShown ? <span className="mx_FacePile_face mx_FacePile_more" /> : null }
return <TextWithTooltip key={member.userId} tooltip={member.name}> { shownMembers.map(m =>
<MemberAvatar member={member} width={28} height={28} /> <MemberAvatar key={m.userId} member={m} width={28} height={28} className="mx_FacePile_face" /> )}
</TextWithTooltip>; </TextWithTooltip>
}) } { onlyKnownUsers && <span className="mx_FacePile_summary">
</div>
{ onlyKnownUsers && <span>
{ _t("%(count)s people you know have already joined", { count: members.length }) } { _t("%(count)s people you know have already joined", { count: members.length }) }
</span> } </span> }
</div> </div>;
}; };
export default FacePile; export default FacePile;

View file

@ -25,6 +25,7 @@ export default class TextWithTooltip extends React.Component {
class: PropTypes.string, class: PropTypes.string,
tooltipClass: PropTypes.string, tooltipClass: PropTypes.string,
tooltip: PropTypes.node.isRequired, tooltip: PropTypes.node.isRequired,
tooltipProps: PropTypes.object,
}; };
constructor() { constructor() {
@ -46,15 +47,17 @@ export default class TextWithTooltip extends React.Component {
render() { render() {
const Tooltip = sdk.getComponent("elements.Tooltip"); const Tooltip = sdk.getComponent("elements.Tooltip");
const {class: className, children, tooltip, tooltipClass, ...props} = this.props; const {class: className, children, tooltip, tooltipClass, tooltipProps, ...props} = this.props;
return ( return (
<span {...props} onMouseOver={this.onMouseOver} onMouseLeave={this.onMouseLeave} className={className}> <span {...props} onMouseOver={this.onMouseOver} onMouseLeave={this.onMouseLeave} className={className}>
{children} {children}
{this.state.hover && <Tooltip {this.state.hover && <Tooltip
{...tooltipProps}
label={tooltip} label={tooltip}
tooltipClassName={tooltipClass} tooltipClassName={tooltipClass}
className={"mx_TextWithTooltip_tooltip"} /> } className={"mx_TextWithTooltip_tooltip"}
/> }
</span> </span>
); );
} }

View file

@ -1916,7 +1916,13 @@
"Please <newIssueLink>create a new issue</newIssueLink> on GitHub so that we can investigate this bug.": "Please <newIssueLink>create a new issue</newIssueLink> on GitHub so that we can investigate this bug.", "Please <newIssueLink>create a new issue</newIssueLink> on GitHub so that we can investigate this bug.": "Please <newIssueLink>create a new issue</newIssueLink> on GitHub so that we can investigate this bug.",
"collapse": "collapse", "collapse": "collapse",
"expand": "expand", "expand": "expand",
"View all %(count)s members|other": "View all %(count)s members",
"View all %(count)s members|one": "View 1 member",
"Including %(commaSeparatedMembers)s": "Including %(commaSeparatedMembers)s",
"%(count)s members including %(commaSeparatedMembers)s|other": "%(count)s members including %(commaSeparatedMembers)s",
"%(count)s members including %(commaSeparatedMembers)s|one": "%(commaSeparatedMembers)s",
"%(count)s people you know have already joined|other": "%(count)s people you know have already joined", "%(count)s people you know have already joined|other": "%(count)s people you know have already joined",
"%(count)s people you know have already joined|one": "%(count)s person you know has already joined",
"Rotate Right": "Rotate Right", "Rotate Right": "Rotate Right",
"Rotate Left": "Rotate Left", "Rotate Left": "Rotate Left",
"Zoom out": "Zoom out", "Zoom out": "Zoom out",