refactored ChannelSelector component
This commit is contained in:
parent
9e9ea41bdd
commit
d3506acd94
4 changed files with 139 additions and 83 deletions
|
@ -9,62 +9,80 @@ import Avatar from '../../atoms/avatar/Avatar';
|
||||||
import NotificationBadge from '../../atoms/badge/NotificationBadge';
|
import NotificationBadge from '../../atoms/badge/NotificationBadge';
|
||||||
import { blurOnBubbling } from '../../atoms/button/script';
|
import { blurOnBubbling } from '../../atoms/button/script';
|
||||||
|
|
||||||
function ChannelSelector({
|
function ChannelSelectorWrapper({
|
||||||
selected, unread, notificationCount, alert,
|
isSelected, onClick, content, options,
|
||||||
iconSrc, imageSrc, roomId, onClick, children,
|
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
|
<div className={`channel-selector${isSelected ? ' channel-selector--selected' : ''}`}>
|
||||||
<button
|
<button
|
||||||
className={`channel-selector__button-wrapper${selected ? ' channel-selector--selected' : ''}`}
|
className="channel-selector__content"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
onMouseUp={(e) => blurOnBubbling(e, '.channel-selector__button-wrapper')}
|
onMouseUp={(e) => blurOnBubbling(e, '.channel-selector__wrapper')}
|
||||||
>
|
>
|
||||||
<div className="channel-selector">
|
{content}
|
||||||
<div className="channel-selector__icon flex--center">
|
</button>
|
||||||
|
<div className="channel-selector__options">{options}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ChannelSelectorWrapper.defaultProps = {
|
||||||
|
options: null,
|
||||||
|
};
|
||||||
|
ChannelSelectorWrapper.propTypes = {
|
||||||
|
isSelected: PropTypes.bool.isRequired,
|
||||||
|
onClick: PropTypes.func.isRequired,
|
||||||
|
content: PropTypes.node.isRequired,
|
||||||
|
options: PropTypes.node,
|
||||||
|
};
|
||||||
|
|
||||||
|
function ChannelSelector({
|
||||||
|
name, roomId, imageSrc, iconSrc,
|
||||||
|
isSelected, isUnread, notificationCount, isAlert,
|
||||||
|
options, onClick,
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<ChannelSelectorWrapper
|
||||||
|
isSelected={isSelected}
|
||||||
|
content={(
|
||||||
|
<>
|
||||||
<Avatar
|
<Avatar
|
||||||
text={children.slice(0, 1)}
|
text={name.slice(0, 1)}
|
||||||
bgColor={colorMXID(roomId)}
|
bgColor={colorMXID(roomId)}
|
||||||
imageSrc={imageSrc}
|
imageSrc={imageSrc}
|
||||||
iconSrc={iconSrc}
|
iconSrc={iconSrc}
|
||||||
size="extra-small"
|
size="extra-small"
|
||||||
/>
|
/>
|
||||||
</div>
|
<Text variant="b1">{name}</Text>
|
||||||
<div className="channel-selector__text-container">
|
{ isUnread && (
|
||||||
<Text variant="b1">{children}</Text>
|
|
||||||
</div>
|
|
||||||
<div className="channel-selector__badge-container">
|
|
||||||
{ unread && (
|
|
||||||
<NotificationBadge
|
<NotificationBadge
|
||||||
alert={alert}
|
alert={isAlert}
|
||||||
content={notificationCount !== 0 ? notificationCount : null}
|
content={notificationCount !== 0 ? notificationCount : null}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</>
|
||||||
</div>
|
)}
|
||||||
</button>
|
options={options}
|
||||||
|
onClick={onClick}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ChannelSelector.defaultProps = {
|
ChannelSelector.defaultProps = {
|
||||||
selected: false,
|
|
||||||
unread: false,
|
|
||||||
notificationCount: 0,
|
|
||||||
alert: false,
|
|
||||||
iconSrc: null,
|
|
||||||
imageSrc: null,
|
imageSrc: null,
|
||||||
|
iconSrc: null,
|
||||||
|
options: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
ChannelSelector.propTypes = {
|
ChannelSelector.propTypes = {
|
||||||
selected: PropTypes.bool,
|
name: PropTypes.string.isRequired,
|
||||||
unread: PropTypes.bool,
|
|
||||||
notificationCount: PropTypes.number,
|
|
||||||
alert: PropTypes.bool,
|
|
||||||
iconSrc: PropTypes.string,
|
|
||||||
imageSrc: PropTypes.string,
|
|
||||||
roomId: PropTypes.string.isRequired,
|
roomId: PropTypes.string.isRequired,
|
||||||
|
imageSrc: PropTypes.string,
|
||||||
|
iconSrc: PropTypes.string,
|
||||||
|
isSelected: PropTypes.bool.isRequired,
|
||||||
|
isUnread: PropTypes.bool.isRequired,
|
||||||
|
notificationCount: PropTypes.number.isRequired,
|
||||||
|
isAlert: PropTypes.bool.isRequired,
|
||||||
|
options: PropTypes.node,
|
||||||
onClick: PropTypes.func.isRequired,
|
onClick: PropTypes.func.isRequired,
|
||||||
children: PropTypes.string.isRequired,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ChannelSelector;
|
export default ChannelSelector;
|
||||||
|
|
|
@ -1,24 +1,35 @@
|
||||||
.channel-selector__button-wrapper {
|
.channel-selector-flex {
|
||||||
display: block;
|
display: flex;
|
||||||
width: calc(100% - var(--sp-extra-tight));
|
align-items: center;
|
||||||
margin-left: auto;
|
}
|
||||||
padding: var(--sp-extra-tight) var(--sp-extra-tight);
|
.channel-selector-flexItem {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.channel-selector {
|
||||||
|
@extend .channel-selector-flex;
|
||||||
|
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
border-radius: var(--bo-radius);
|
border-radius: var(--bo-radius);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
[dir=rtl] & {
|
&--selected {
|
||||||
|
background-color: var(--bg-surface);
|
||||||
|
border-color: var(--bg-surface-border);
|
||||||
|
|
||||||
margin: {
|
& .channel-selector__options {
|
||||||
left: 0;
|
display: flex;
|
||||||
right: auto;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (hover: hover) {
|
@media (hover: hover) {
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: var(--bg-surface-hover);
|
background-color: var(--bg-surface-hover);
|
||||||
|
& .channel-selector__options {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&:focus {
|
&:focus {
|
||||||
|
@ -28,33 +39,50 @@
|
||||||
&:active {
|
&:active {
|
||||||
background-color: var(--bg-surface-active);
|
background-color: var(--bg-surface-active);
|
||||||
}
|
}
|
||||||
|
&--selected:hover,
|
||||||
|
&--selected:focus,
|
||||||
|
&--selected:active {
|
||||||
|
background-color: var(--bg-surface);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.channel-selector {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
&__icon {
|
.channel-selector__content {
|
||||||
width: 24px;
|
@extend .channel-selector-flexItem;
|
||||||
height: 24px;
|
@extend .channel-selector-flex;
|
||||||
.avatar__border {
|
padding: 0 var(--sp-extra-tight);
|
||||||
|
min-height: 40px;
|
||||||
|
cursor: inherit;
|
||||||
|
|
||||||
|
& > .avatar-container .avatar__bordered {
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
&__text-container {
|
& > .text {
|
||||||
flex: 1;
|
@extend .channel-selector-flexItem;
|
||||||
min-width: 0;
|
|
||||||
margin: 0 var(--sp-extra-tight);
|
margin: 0 var(--sp-extra-tight);
|
||||||
|
|
||||||
& .text {
|
|
||||||
color: var(--tc-surface-normal);
|
color: var(--tc-surface-normal);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
.channel-selector__options {
|
||||||
|
@extend .channel-selector-flex;
|
||||||
|
display: none;
|
||||||
|
margin-right: var(--sp-ultra-tight);
|
||||||
|
|
||||||
|
[dir=rtl] & {
|
||||||
|
margin-right: 0;
|
||||||
|
margin-left: var(--sp-ultra-tight);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:empty {
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .ic-btn-surface {
|
||||||
|
padding: 6px;
|
||||||
|
border-radius: calc(var(--bo-radius) / 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.channel-selector--selected {
|
|
||||||
background-color: var(--bg-surface);
|
|
||||||
border-color: var(--bg-surface-border);
|
|
||||||
}
|
|
|
@ -102,6 +102,9 @@ function renderSelector(room, roomId, isSelected, isDM) {
|
||||||
return (
|
return (
|
||||||
<ChannelSelector
|
<ChannelSelector
|
||||||
key={roomId}
|
key={roomId}
|
||||||
|
name={room.name}
|
||||||
|
roomId={roomId}
|
||||||
|
imageSrc={isDM ? imageSrc : null}
|
||||||
iconSrc={
|
iconSrc={
|
||||||
isDM
|
isDM
|
||||||
? null
|
? null
|
||||||
|
@ -112,16 +115,12 @@ function renderSelector(room, roomId, isSelected, isDM) {
|
||||||
return (room.getJoinRule() === 'invite' ? HashLockIC : HashIC);
|
return (room.getJoinRule() === 'invite' ? HashLockIC : HashIC);
|
||||||
})()
|
})()
|
||||||
}
|
}
|
||||||
imageSrc={isDM ? imageSrc : null}
|
isSelected={isSelected}
|
||||||
roomId={roomId}
|
isUnread={doesRoomHaveUnread(room)}
|
||||||
unread={doesRoomHaveUnread(room)}
|
|
||||||
onClick={() => selectRoom(roomId)}
|
|
||||||
notificationCount={room.getUnreadNotificationCount('total')}
|
notificationCount={room.getUnreadNotificationCount('total')}
|
||||||
alert={room.getUnreadNotificationCount('highlight') !== 0}
|
isAlert={room.getUnreadNotificationCount('highlight') !== 0}
|
||||||
selected={isSelected}
|
onClick={() => selectRoom(roomId)}
|
||||||
>
|
/>
|
||||||
{room.name}
|
|
||||||
</ChannelSelector>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,18 @@
|
||||||
.channels-container {
|
.channels-container {
|
||||||
padding-bottom: var(--sp-extra-loose);
|
padding-bottom: var(--sp-extra-loose);
|
||||||
|
|
||||||
& > .channel-selector__button-wrapper:first-child {
|
& > .channel-selector {
|
||||||
|
width: calc(100% - var(--sp-extra-tight));
|
||||||
|
margin-left: auto;
|
||||||
|
|
||||||
|
[dir=rtl] & {
|
||||||
|
margin-left: 0;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .channel-selector:first-child {
|
||||||
margin-top: var(--sp-extra-tight);
|
margin-top: var(--sp-extra-tight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue