Make the unread badge component more reusable (#12163)

Add a paramter to make it a dot rather than a badge rather than mangling
it to a dot with CSS in EventTile. Move it to a place in the DOM that reflects
where it's actually supposed to sit rather than repositioning it with CSS.
Tweak sizes to match what figma says (8px everywhere for dots rather than 6px in
some places as it was).
This commit is contained in:
David Baker 2024-01-23 14:39:50 +00:00 committed by GitHub
parent 4e68b91515
commit d110660dc3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 19 additions and 36 deletions

View file

@ -1053,23 +1053,6 @@ $left-gutter: 64px;
pointer-events: none; /* ensures the title for the sender name can be correctly displayed */ pointer-events: none; /* ensures the title for the sender name can be correctly displayed */
} }
/* Display notification dot */
&[data-notification]::before,
.mx_NotificationBadge {
position: absolute;
$notification-inset-block-start: 14px; /* 14px: align the dot with the timestamp row */
/* !important to fix overly specific CSS selector applied on mx_NotificationBadge */
width: $notification-dot-size !important;
height: $notification-dot-size !important;
border-radius: 50%;
inset: $notification-inset-block-start $spacing-8 auto auto;
}
.mx_NotificationBadge_count {
display: none;
}
&[data-notification="total"]::before { &[data-notification="total"]::before {
background-color: $room-icon-unread-color; background-color: $room-icon-unread-color;
} }
@ -1441,14 +1424,6 @@ $left-gutter: 64px;
margin-bottom: $spacing-4; /* 1/4 of the non-compact margin-bottom */ margin-bottom: $spacing-4; /* 1/4 of the non-compact margin-bottom */
} }
} }
&[data-shape="ThreadsList"][data-notification]::before,
.mx_NotificationBadge {
/* stylelint-disable-next-line declaration-colon-space-after */
inset-block-start: calc(
$notification-inset-block-start - var(--MatrixChat_useCompactLayout_group-padding-top)
);
}
} }
} }

View file

@ -41,11 +41,13 @@ limitations under the License.
/* These are the 3 background types */ /* These are the 3 background types */
&.mx_NotificationBadge_dot { &.mx_NotificationBadge_dot {
background-color: $primary-content; /* increased visibility */ width: 8px;
height: 8px;
border-radius: 8px;
width: 6px; .mx_NotificationBadge_count {
height: 6px; display: none;
border-radius: 6px; }
} }
&.mx_NotificationBadge_knocked { &.mx_NotificationBadge_knocked {

View file

@ -1308,6 +1308,11 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
"" ""
)} )}
{timestamp} {timestamp}
<UnreadNotificationBadge
room={room || undefined}
threadId={this.props.mxEvent.getId()}
type="dot"
/>
</div> </div>
{isRenderingNotification && room ? ( {isRenderingNotification && room ? (
<div className="mx_EventTile_avatar"> <div className="mx_EventTile_avatar">
@ -1336,7 +1341,6 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
)} )}
{msgOption} {msgOption}
<UnreadNotificationBadge room={room || undefined} threadId={this.props.mxEvent.getId()} />
</>, </>,
); );
} }

View file

@ -28,6 +28,7 @@ interface Props {
count: number; count: number;
level: NotificationLevel; level: NotificationLevel;
knocked?: boolean; knocked?: boolean;
type?: "badge" | "dot";
} }
interface ClickableProps extends Props { interface ClickableProps extends Props {
@ -39,7 +40,7 @@ interface ClickableProps extends Props {
} }
export const StatelessNotificationBadge = forwardRef<HTMLDivElement, XOR<Props, ClickableProps>>( export const StatelessNotificationBadge = forwardRef<HTMLDivElement, XOR<Props, ClickableProps>>(
({ symbol, count, level, knocked, ...props }, ref) => { ({ symbol, count, level, knocked, type = "badge", ...props }, ref) => {
const hideBold = useSettingValue("feature_hidebold"); const hideBold = useSettingValue("feature_hidebold");
// Don't show a badge if we don't need to // Don't show a badge if we don't need to
@ -59,10 +60,10 @@ export const StatelessNotificationBadge = forwardRef<HTMLDivElement, XOR<Props,
mx_NotificationBadge: true, mx_NotificationBadge: true,
mx_NotificationBadge_visible: isEmptyBadge || knocked ? true : hasUnreadCount, mx_NotificationBadge_visible: isEmptyBadge || knocked ? true : hasUnreadCount,
mx_NotificationBadge_highlighted: level >= NotificationLevel.Highlight, mx_NotificationBadge_highlighted: level >= NotificationLevel.Highlight,
mx_NotificationBadge_dot: isEmptyBadge && !knocked, mx_NotificationBadge_dot: (isEmptyBadge && !knocked) || type === "dot",
mx_NotificationBadge_knocked: knocked, mx_NotificationBadge_knocked: knocked,
mx_NotificationBadge_2char: symbol && symbol.length > 0 && symbol.length < 3, mx_NotificationBadge_2char: type === "badge" && symbol && symbol.length > 0 && symbol.length < 3,
mx_NotificationBadge_3char: symbol && symbol.length > 2, mx_NotificationBadge_3char: type === "badge" && symbol && symbol.length > 2,
}); });
if (props.onClick) { if (props.onClick) {

View file

@ -23,10 +23,11 @@ import { StatelessNotificationBadge } from "./StatelessNotificationBadge";
interface Props { interface Props {
room?: Room; room?: Room;
threadId?: string; threadId?: string;
type?: "badge" | "dot";
} }
export function UnreadNotificationBadge({ room, threadId }: Props): JSX.Element { export function UnreadNotificationBadge({ room, threadId, type }: Props): JSX.Element {
const { symbol, count, level } = useUnreadNotifications(room, threadId); const { symbol, count, level } = useUnreadNotifications(room, threadId);
return <StatelessNotificationBadge symbol={symbol} count={count} level={level} />; return <StatelessNotificationBadge symbol={symbol} count={count} level={level} type={type} />;
} }