Merge pull request #5898 from matrix-org/t3chguy/fix/16976
Iterate the spaces face pile design
This commit is contained in:
commit
d9dac7b261
5 changed files with 71 additions and 45 deletions
|
@ -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');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
return <div {...props} className="mx_FacePile">
|
const shownMembers = sortBy(members.filter(m => m.userId !== cli.getUserId()), iteratees).slice(0, numShown);
|
||||||
<div className="mx_FacePile_faces">
|
if (shownMembers.length < 1) return null;
|
||||||
{ shownMembers.map(member => {
|
|
||||||
return <TextWithTooltip key={member.userId} tooltip={member.name}>
|
// We reverse the order of the shown faces in CSS to simplify their visual overlap,
|
||||||
<MemberAvatar member={member} width={28} height={28} />
|
// reverse members in tooltip order to make the order between the two match up.
|
||||||
</TextWithTooltip>;
|
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>
|
||||||
{ onlyKnownUsers && <span>
|
<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">
|
||||||
|
<TextWithTooltip class="mx_FacePile_faces" tooltip={tooltip} tooltipProps={{ yOffset: 32 }}>
|
||||||
|
{ members.length > numShown ? <span className="mx_FacePile_face mx_FacePile_more" /> : null }
|
||||||
|
{ shownMembers.map(m =>
|
||||||
|
<MemberAvatar key={m.userId} member={m} width={28} height={28} className="mx_FacePile_face" /> )}
|
||||||
|
</TextWithTooltip>
|
||||||
|
{ onlyKnownUsers && <span className="mx_FacePile_summary">
|
||||||
{ _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;
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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",
|
||||||
|
|
Loading…
Reference in a new issue