Room list: add activity marker to sections (#33024)

* feat: add unread status to section view

* feat: add unread tracking in room list section

* feat: populate rooms into section header vm

* test: add units for unread in section view model

* test(e2e): add unread tests
This commit is contained in:
Florian Duros
2026-04-06 19:05:45 +00:00
committed by GitHub
parent e53a148da2
commit 46bff1f9e6
9 changed files with 220 additions and 6 deletions
@@ -141,7 +141,8 @@
},
"room_options": "Room Options",
"section_header": {
"toggle": "Toggle %(section)s section"
"toggle": "Toggle %(section)s section",
"toggle_unread": "Toggle %(section)s section with unread room(s)"
},
"show_message_previews": "Show message previews",
"sort": "Sort",
@@ -46,6 +46,11 @@
transform: rotate(90deg);
}
}
&.unread {
font: var(--cpd-font-body-md-semibold);
color: var(--cpd-color-text-primary);
}
}
.container {
@@ -56,6 +56,7 @@ const meta = {
title: "Favourites",
isExpanded: true,
isFocused: false,
isUnread: false,
onClick: fn(),
onFocus: fn(),
sectionIndex: 1,
@@ -107,3 +108,9 @@ export const LastHeaderCollapsed: Story = {
sectionIndex: 2,
},
};
export const Unread: Story = {
args: {
isUnread: true,
},
};
@@ -25,6 +25,8 @@ export interface RoomListSectionHeaderViewSnapshot {
title: string;
/** Whether the section is currently expanded. */
isExpanded: boolean;
/** Whether the section is unread (has any unread rooms) */
isUnread: boolean;
}
/**
@@ -89,7 +91,7 @@ export const RoomListSectionHeaderView = memo(function RoomListSectionHeaderView
roomCountInSection,
}: Readonly<RoomListSectionHeaderViewProps>): JSX.Element {
const { translate: _t } = useI18n();
const { id, title, isExpanded } = useViewModel(vm);
const { id, title, isExpanded, isUnread } = useViewModel(vm);
const isLastSection = sectionIndex === sectionCount - 1;
return (
@@ -104,12 +106,17 @@ export const RoomListSectionHeaderView = memo(function RoomListSectionHeaderView
[styles.firstHeader]: sectionIndex === 0,
// If the section is collapsed and it's the last one
[styles.lastHeader]: !isExpanded && isLastSection,
[styles.unread]: isUnread,
})}
onClick={vm.onClick}
aria-expanded={isExpanded}
onFocus={(e) => onFocus(id, e)}
tabIndex={isFocused ? 0 : -1}
aria-label={_t("room_list|section_header|toggle", { section: title })}
aria-label={
isUnread
? _t("room_list|section_header|toggle_unread", { section: title })
: _t("room_list|section_header|toggle", { section: title })
}
>
<Flex className={styles.container} align="center" gap="var(--cpd-space-0-5x)">
<ChevronRightIcon width="24px" height="24px" fill="var(--cpd-color-icon-secondary)" />