Room list: add collapse/expand all sections (#33318)
* chore: update compound design tokens * feat(sc): add collapse/expand button to room list header * feat: add new events to broadcast section state * feat(vm): add expand/collpase event to room list events * test: add e2e tests * chore: fix company name in copyright * chore: use two differant actions for collapse/expand * Update apps/web/src/viewmodels/room-list/RoomListHeaderViewModel.ts Co-authored-by: Michael Telatynski <7t3chguy@gmail.com> * test: fix existing tests --------- Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
co-authored by
Michael Telatynski
parent
a7ab72af11
commit
c2e5aa7adc
BIN
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
@@ -100,6 +100,7 @@
|
||||
},
|
||||
"appearance": "Appearance",
|
||||
"chat_moved": "Chat moved",
|
||||
"collapse_all_sections": "Collapse all sections",
|
||||
"collapse_filters": "Collapse filter list",
|
||||
"empty": {
|
||||
"no_chats": "No chats yet",
|
||||
@@ -118,6 +119,7 @@
|
||||
"show_activity": "See all activity",
|
||||
"show_chats": "Show all chats"
|
||||
},
|
||||
"expand_all_sections": "Expand all sections",
|
||||
"expand_filters": "Expand filter list",
|
||||
"filters": {
|
||||
"favourite": "Favourites",
|
||||
|
||||
+9
@@ -31,6 +31,7 @@ const RoomListHeaderViewWrapperImpl = ({
|
||||
sort,
|
||||
toggleMessagePreview,
|
||||
createSection,
|
||||
collapseOrExpandSections,
|
||||
...rest
|
||||
}: RoomListHeaderProps): JSX.Element => {
|
||||
const vm = useMockedViewModel(rest, {
|
||||
@@ -44,6 +45,7 @@ const RoomListHeaderViewWrapperImpl = ({
|
||||
openSpacePreferences,
|
||||
toggleMessagePreview,
|
||||
createSection,
|
||||
collapseOrExpandSections,
|
||||
});
|
||||
return <RoomListHeaderView vm={vm} />;
|
||||
};
|
||||
@@ -65,6 +67,7 @@ const meta = {
|
||||
openSpacePreferences: fn(),
|
||||
toggleMessagePreview: fn(),
|
||||
createSection: fn(),
|
||||
collapseOrExpandSections: fn(),
|
||||
},
|
||||
parameters: {
|
||||
design: {
|
||||
@@ -109,3 +112,9 @@ export const PlusIcon: Story = {
|
||||
useComposeIcon: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const CollapseSections: Story = {
|
||||
args: {
|
||||
collapseSections: "collapse",
|
||||
},
|
||||
};
|
||||
|
||||
+8
-1
@@ -12,7 +12,7 @@ import React from "react";
|
||||
|
||||
import * as stories from "./RoomListHeaderView.stories";
|
||||
|
||||
const { Default, NoComposeMenu, NoSpaceMenu } = composeStories(stories);
|
||||
const { Default, NoComposeMenu, NoSpaceMenu, CollapseSections } = composeStories(stories);
|
||||
|
||||
describe("RoomListHeaderView", () => {
|
||||
it("renders the default state", () => {
|
||||
@@ -29,4 +29,11 @@ describe("RoomListHeaderView", () => {
|
||||
const { container } = render(<NoSpaceMenu />);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should bind the collapse all sections action", () => {
|
||||
const { getByRole } = render(<CollapseSections />);
|
||||
const collapseButton = getByRole("button", { name: "Collapse all sections" });
|
||||
collapseButton.click();
|
||||
expect(CollapseSections.args?.collapseOrExpandSections).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -9,6 +9,7 @@ import React, { type JSX } from "react";
|
||||
import { IconButton, H1 } from "@vector-im/compound-web";
|
||||
import ComposeIcon from "@vector-im/compound-design-tokens/assets/web/icons/compose";
|
||||
import PlusIcon from "@vector-im/compound-design-tokens/assets/web/icons/plus";
|
||||
import CollapseAllIcon from "@vector-im/compound-design-tokens/assets/web/icons/collapse-all";
|
||||
|
||||
import { type ViewModel, useViewModel } from "../../core/viewmodel";
|
||||
import { Flex } from "../../core/utils/Flex";
|
||||
@@ -21,6 +22,11 @@ import styles from "./RoomListHeaderView.module.css";
|
||||
*/
|
||||
export type SortOption = "recent" | "alphabetical" | "unread-first";
|
||||
|
||||
/**
|
||||
* The available options for collapsing sections in the room list.
|
||||
*/
|
||||
export type CollapseSectionsOption = "collapse" | "expand";
|
||||
|
||||
export interface RoomListHeaderViewSnapshot {
|
||||
/**
|
||||
* The title of the room list
|
||||
@@ -68,6 +74,12 @@ export interface RoomListHeaderViewSnapshot {
|
||||
* Whether to use the compose icon instead of the create icon.
|
||||
*/
|
||||
useComposeIcon: boolean;
|
||||
/**
|
||||
* If "collapse", an icon to collapse all sections is shown.
|
||||
* If "expand", an icon to expand all sections is shown.
|
||||
* If undefined, no icon are shown.
|
||||
*/
|
||||
collapseSections?: CollapseSectionsOption;
|
||||
}
|
||||
|
||||
export interface RoomListHeaderViewActions {
|
||||
@@ -111,6 +123,10 @@ export interface RoomListHeaderViewActions {
|
||||
* Create a new section in the room list.
|
||||
*/
|
||||
createSection: () => void;
|
||||
/**
|
||||
* Collapse or expand all sections in the room list depending on the current state.
|
||||
*/
|
||||
collapseOrExpandSections: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -136,7 +152,7 @@ interface RoomListHeaderViewProps {
|
||||
*/
|
||||
export function RoomListHeaderView({ vm }: Readonly<RoomListHeaderViewProps>): JSX.Element {
|
||||
const { translate: _t } = useI18n();
|
||||
const { title, displaySpaceMenu, displayComposeMenu, useComposeIcon } = useViewModel(vm);
|
||||
const { title, displaySpaceMenu, displayComposeMenu, useComposeIcon, collapseSections } = useViewModel(vm);
|
||||
|
||||
return (
|
||||
<Flex
|
||||
@@ -155,6 +171,20 @@ export function RoomListHeaderView({ vm }: Readonly<RoomListHeaderViewProps>): J
|
||||
</Flex>
|
||||
<Flex align="center" gap="var(--cpd-space-2x)">
|
||||
<OptionMenuView vm={vm} />
|
||||
{collapseSections && (
|
||||
<IconButton
|
||||
size="28px"
|
||||
style={{ padding: "4px" }}
|
||||
onClick={() => vm.collapseOrExpandSections()}
|
||||
tooltip={
|
||||
collapseSections === "collapse"
|
||||
? _t("room_list|collapse_all_sections")
|
||||
: _t("room_list|expand_all_sections")
|
||||
}
|
||||
>
|
||||
<CollapseAllIcon color="var(--cpd-color-icon-secondary)" aria-hidden />
|
||||
</IconButton>
|
||||
)}
|
||||
|
||||
{/* If we don't display the compose menu, it means that the user can only send DM */}
|
||||
{displayComposeMenu ? (
|
||||
|
||||
@@ -10,5 +10,6 @@ export type {
|
||||
RoomListHeaderViewSnapshot,
|
||||
RoomListHeaderViewActions,
|
||||
SortOption,
|
||||
CollapseSectionsOption,
|
||||
} from "./RoomListHeaderView";
|
||||
export { RoomListHeaderView } from "./RoomListHeaderView";
|
||||
|
||||
@@ -24,6 +24,7 @@ export class MockedViewModel extends MockViewModel<RoomListHeaderViewSnapshot> i
|
||||
public openSpacePreferences = vi.fn<() => void>();
|
||||
public toggleMessagePreview = vi.fn<() => void>();
|
||||
public createSection = vi.fn<() => void>();
|
||||
public collapseOrExpandSections = vi.fn<() => void>();
|
||||
}
|
||||
|
||||
export { defaultSnapshot } from "./default-snapshot";
|
||||
|
||||
Reference in New Issue
Block a user