Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Add room topic to right panel room info #12503

Merged
merged 8 commits into from
May 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we know what's appeared in the background here? Is this because of things shifting due to stable scrollbar gutter or something? It just seems unrelated to the change.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah its the bottom right corner background under the modal, presumably due to the scrollbar shift in the right panel

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough, I guess this is what it is.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions res/css/views/right_panel/_BaseCard.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ limitations under the License.
min-height: 0;
width: 100%;
height: 100%;
scrollbar-gutter: stable;
}

.mx_BaseCard_Group {
Expand Down
46 changes: 46 additions & 0 deletions res/css/views/right_panel/_RoomSummaryCard.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,52 @@ limitations under the License.
}
}

.mx_RoomSummaryCard_topic {
padding: 0 12px;

.mx_Box {
width: 100%;
}

.mx_RoomSummaryCard_topic_container {
display: flex;
}

.mx_RoomSummaryCard_topic_edit {
width: max-content;
}

p {
white-space: pre-wrap;
width: 100%;
min-width: 0;
margin: 0;
}

a {
cursor: pointer;
}

.mx_RoomSummaryCard_topic_chevron {
transition: transform 0.3s;
}

&.mx_RoomSummaryCard_topic_collapsed {
p {
overflow: hidden;
text-overflow: ellipsis;
white-space: normal;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}

.mx_RoomSummaryCard_topic_chevron {
transform: rotate(-90deg);
}
}
}

.mx_RoomSummaryCard_appsGroup {
.mx_RoomSummaryCard_Button {
/* this button is special so we have to override some of the original styling */
Expand Down
10 changes: 7 additions & 3 deletions src/HtmlUtils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -461,9 +461,13 @@ export function topicToHtml(
emojiBodyElements = formatEmojis(topic, false);
}

return isFormattedTopic ? (
<span ref={ref} dangerouslySetInnerHTML={{ __html: safeTopic }} dir="auto" />
) : (
if (isFormattedTopic) {
if (!safeTopic) return null;
return <span ref={ref} dangerouslySetInnerHTML={{ __html: safeTopic }} dir="auto" />;
}

if (!emojiBodyElements && !topic) return null;
return (
<span ref={ref} dir="auto">
{emojiBodyElements || topic}
</span>
Expand Down
20 changes: 12 additions & 8 deletions src/components/views/elements/RoomTopic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,17 @@ interface IProps extends React.HTMLProps<HTMLDivElement> {
room: Room;
}

export function onRoomTopicLinkClick(e: React.MouseEvent): void {
const anchor = e.target as HTMLLinkElement;
const localHref = tryTransformPermalinkToLocalHref(anchor.href);

if (localHref !== anchor.href) {
// it could be converted to a localHref -> therefore handle locally
e.preventDefault();
window.location.hash = localHref;
}
}

export default function RoomTopic({ room, className, ...props }: IProps): JSX.Element {
const client = useContext(MatrixClientContext);
const ref = useRef<HTMLDivElement>(null);
Expand All @@ -54,14 +65,7 @@ export default function RoomTopic({ room, className, ...props }: IProps): JSX.El
return;
}

const anchor = e.target as HTMLLinkElement;
const localHref = tryTransformPermalinkToLocalHref(anchor.href);

if (localHref !== anchor.href) {
// it could be converted to a localHref -> therefore handle locally
e.preventDefault();
window.location.hash = localHref;
}
onRoomTopicLinkClick(e);
},
[props],
);
Expand Down
99 changes: 97 additions & 2 deletions src/components/views/right_panel/RoomSummaryCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,19 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import React, { useCallback, useContext, useEffect, useMemo, useState } from "react";
import React, { SyntheticEvent, useCallback, useContext, useEffect, useMemo, useState } from "react";
import classNames from "classnames";
import { MenuItem, Tooltip, Separator, ToggleMenuItem, Text, Badge, Heading } from "@vector-im/compound-web";
import {
MenuItem,
Tooltip,
Separator,
ToggleMenuItem,
Text,
Badge,
Heading,
IconButton,
Link,
} from "@vector-im/compound-web";
import { Icon as SearchIcon } from "@vector-im/compound-design-tokens/icons/search.svg";
import { Icon as FavouriteIcon } from "@vector-im/compound-design-tokens/icons/favourite.svg";
import { Icon as UserAddIcon } from "@vector-im/compound-design-tokens/icons/user-add.svg";
Expand All @@ -32,6 +42,7 @@ import { Icon as LockIcon } from "@vector-im/compound-design-tokens/icons/lock-s
import { Icon as LockOffIcon } from "@vector-im/compound-design-tokens/icons/lock-off.svg";
import { Icon as PublicIcon } from "@vector-im/compound-design-tokens/icons/public.svg";
import { Icon as ErrorIcon } from "@vector-im/compound-design-tokens/icons/error.svg";
import { Icon as ChevronDownIcon } from "@vector-im/compound-design-tokens/icons/chevron-down.svg";
import { EventType, JoinRule, Room, RoomStateEvent } from "matrix-js-sdk/src/matrix";

import MatrixClientContext from "../../../contexts/MatrixClientContext";
Expand Down Expand Up @@ -74,6 +85,10 @@ import { canInviteTo } from "../../../utils/room/canInviteTo";
import { inviteToRoom } from "../../../utils/room/inviteToRoom";
import { useAccountData } from "../../../hooks/useAccountData";
import { useRoomState } from "../../../hooks/useRoomState";
import { useTopic } from "../../../hooks/room/useTopic";
import { Linkify, topicToHtml } from "../../../HtmlUtils";
import { Box } from "../../utils/Box";
import { onRoomTopicLinkClick } from "../elements/RoomTopic";

interface IProps {
room: Room;
Expand Down Expand Up @@ -271,6 +286,84 @@ const onRoomSettingsClick = (ev: Event): void => {
PosthogTrackers.trackInteraction("WebRightPanelRoomInfoSettingsButton", ev);
};

const RoomTopic: React.FC<Pick<IProps, "room">> = ({ room }): JSX.Element | null => {
const [expanded, setExpanded] = useState(false);

const topic = useTopic(room);
const body = topicToHtml(topic?.text, topic?.html);

const onEditClick = (e: SyntheticEvent): void => {
e.preventDefault();
e.stopPropagation();
defaultDispatcher.dispatch({ action: "open_room_settings" });
};

if (!body) {
return (
<Flex
as="section"
direction="column"
justify="center"
gap="var(--cpd-space-2x)"
className="mx_RoomSummaryCard_topic"
>
<Box flex="1">
<Link kind="primary" onClick={onEditClick}>
<Text size="sm" weight="regular">
{_t("right_panel|add_topic")}
</Text>
</Link>
</Box>
</Flex>
);
}

const content = expanded ? <Linkify>{body}</Linkify> : body;
return (
<Flex
as="section"
direction="column"
justify="center"
gap="var(--cpd-space-2x)"
className={classNames("mx_RoomSummaryCard_topic", {
mx_RoomSummaryCard_topic_collapsed: !expanded,
})}
>
<Box flex="1" className="mx_RoomSummaryCard_topic_container">
<Text
size="sm"
weight="regular"
onClick={(ev: React.MouseEvent): void => {
if (ev.target instanceof HTMLAnchorElement) {
onRoomTopicLinkClick(ev);
return;
}
setExpanded(!expanded);
}}
>
{content}
</Text>
<IconButton
className="mx_RoomSummaryCard_topic_chevron"
size="24px"
onClick={() => setExpanded(!expanded)}
>
<ChevronDownIcon />
</IconButton>
</Box>
{expanded && (
<Box flex="1" className="mx_RoomSummaryCard_topic_edit">
<Link kind="primary" onClick={onEditClick}>
<Text size="sm" weight="regular">
{_t("action|edit")}
</Text>
</Link>
</Box>
)}
</Flex>
);
};

const RoomSummaryCard: React.FC<IProps> = ({ room, permalinkCreator, onClose, onSearchClick }) => {
const cli = useContext(MatrixClientContext);

Expand Down Expand Up @@ -382,6 +475,8 @@ const RoomSummaryCard: React.FC<IProps> = ({ room, permalinkCreator, onClose, on
</Badge>
)}
</Flex>

<RoomTopic room={room} />
</header>
);

Expand Down
1 change: 1 addition & 0 deletions src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -1821,6 +1821,7 @@
},
"right_panel": {
"add_integrations": "Add widgets, bridges & bots",
"add_topic": "Add topic",
"edit_integrations": "Edit widgets, bridges & bots",
"export_chat_button": "Export chat",
"files_button": "Files",
Expand Down
24 changes: 4 additions & 20 deletions test/components/structures/__snapshots__/RoomView-test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,7 @@ exports[`RoomView for a local room in state CREATING should match the snapshot 1
class="mx_LegacyRoomHeader_topic mx_RoomTopic"
dir="auto"
tabindex="0"
>
<span
dir="auto"
/>
</div>
/>
</div>
</header>
<div
Expand Down Expand Up @@ -129,11 +125,7 @@ exports[`RoomView for a local room in state ERROR should match the snapshot 1`]
class="mx_LegacyRoomHeader_topic mx_RoomTopic"
dir="auto"
tabindex="0"
>
<span
dir="auto"
/>
</div>
/>
</div>
</header>
<main
Expand Down Expand Up @@ -296,11 +288,7 @@ exports[`RoomView for a local room in state NEW should match the snapshot 1`] =
class="mx_LegacyRoomHeader_topic mx_RoomTopic"
dir="auto"
tabindex="0"
>
<span
dir="auto"
/>
</div>
/>
</div>
</header>
<main
Expand Down Expand Up @@ -547,11 +535,7 @@ exports[`RoomView for a local room in state NEW that is encrypted should match t
class="mx_LegacyRoomHeader_topic mx_RoomTopic"
dir="auto"
tabindex="0"
>
<span
dir="auto"
/>
</div>
/>
</div>
</header>
<main
Expand Down
34 changes: 34 additions & 0 deletions test/components/views/right_panel/RoomSummaryCard-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,40 @@ describe("<RoomSummaryCard />", () => {
expect(container).toMatchSnapshot();
});

it("renders the room topic in the summary", () => {
room.currentState.setStateEvents([
new MatrixEvent({
type: "m.room.topic",
room_id: roomId,
sender: userId,
content: {
topic: "This is the room's topic.",
},
state_key: "",
}),
]);
const { container } = getComponent();
expect(container).toMatchSnapshot();
});

it("has button to edit topic when expanded", () => {
room.currentState.setStateEvents([
new MatrixEvent({
type: "m.room.topic",
room_id: roomId,
sender: userId,
content: {
topic: "This is the room's topic.",
},
state_key: "",
}),
]);
const { container, getByText } = getComponent();
fireEvent.click(screen.getByText("This is the room's topic."));
expect(getByText("Edit")).toBeInTheDocument();
expect(container).toMatchSnapshot();
});

it("opens the search", async () => {
const onSearchClick = jest.fn();
const { getByLabelText } = getComponent({
Expand Down
Loading
Loading