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

Commit

Permalink
Make long room topic readable
Browse files Browse the repository at this point in the history
Fixes element-hq/element-web#9623

Clicking the room topic now displays a modal showing the full room topic
  • Loading branch information
Germain Souquet committed May 6, 2022
1 parent 6617ea3 commit 5b047a6
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 41 deletions.
6 changes: 6 additions & 0 deletions res/css/views/rooms/_RoomHeader.scss
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ limitations under the License.
cursor: pointer;
}

.mx_RoomTopic {
position: relative;
}

.mx_RoomHeader_topic {
$lineHeight: $font-16px;
$lines: 2;
Expand Down Expand Up @@ -209,6 +213,7 @@ limitations under the License.
.mx_RoomHeader_appsButton::before {
mask-image: url('$(res)/img/element-icons/room/apps.svg');
}

.mx_RoomHeader_appsButton_highlight::before {
background-color: $accent;
}
Expand Down Expand Up @@ -239,6 +244,7 @@ limitations under the License.
padding: 0;
margin: 0;
}

.mx_RoomHeader {
overflow: hidden;
}
Expand Down
8 changes: 1 addition & 7 deletions src/components/structures/SpaceRoomView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -254,13 +254,7 @@ const SpaceLanding = ({ space }: { space: Room }) => {
{ settingsButton }
</div>
</div>
<RoomTopic room={space}>
{ (topic, ref) => (
<div className="mx_SpaceRoomView_landing_topic" ref={ref}>
{ topic }
</div>
) }
</RoomTopic>
<RoomTopic room={space} className="mx_SpaceRoomView_landing_topic" />

<SpaceHierarchy space={space} showRoom={showRoom} additionalButtons={addRoomButton} />
</div>;
Expand Down
96 changes: 74 additions & 22 deletions src/components/views/elements/RoomTopic.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2021 The Matrix.org Foundation C.I.C.
Copyright 2021 - 2022 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand All @@ -14,35 +14,87 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import React, { useEffect, useState } from "react";
import { EventType } from "matrix-js-sdk/src/@types/event";
import React, { useCallback, useContext, useRef } from "react";
import { Room } from "matrix-js-sdk/src/models/room";
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import classNames from "classnames";
import { defer } from "lodash";

import { useTypedEventEmitter } from "../../../hooks/useEventEmitter";
import { linkifyElement } from "../../../HtmlUtils";
import { useTopic } from "../../../hooks/room/useTopic";
import useHover from "../../../hooks/useHover";
import Tooltip, { Alignment } from "./Tooltip";
import { _t } from "../../../languageHandler";
import dis from "../../../dispatcher/dispatcher";
import { Action } from "../../../dispatcher/actions";
import Modal from "../../../Modal";
import InfoDialog from "../dialogs/InfoDialog";
import { useDispatcher } from "../../../hooks/useDispatcher";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import AccessibleButton from "./AccessibleButton";

interface IProps {
interface IProps extends React.HTMLProps<HTMLDivElement> {
room?: Room;
children?(topic: string, ref: (element: HTMLElement) => void): JSX.Element;
}

export const getTopic = room => room?.currentState?.getStateEvents(EventType.RoomTopic, "")?.getContent()?.topic;
export default function RoomTopic({
room,
...props
}: IProps) {
const client = useContext(MatrixClientContext);
const ref = useRef<HTMLDivElement>();
const hovered = useHover(ref);

const RoomTopic = ({ room, children }: IProps): JSX.Element => {
const [topic, setTopic] = useState(getTopic(room));
useTypedEventEmitter(room.currentState, RoomStateEvent.Events, (ev: MatrixEvent) => {
if (ev.getType() !== EventType.RoomTopic) return;
setTopic(getTopic(room));
const topic = useTopic(room);

const onClick = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
props.onClick?.(e);
const target = e.target as HTMLElement;
if (target.tagName.toUpperCase() === "A") {
return;
}

dis.fire(Action.ShowRoomTopic);
}, [props]);

useDispatcher(dis, (payload) => {
if (payload.action === Action.ShowRoomTopic) {
const canSetTopic = room.currentState.maySendStateEvent('m.room.topic', client.getUserId());

const modal = Modal.createDialog(InfoDialog, {
title: room.name,
description: <div>
<p className="mx_jsTopicNode">{ topic }</p>
{ canSetTopic && <AccessibleButton
kind="primary_outline"
onClick={() => {
modal.close();
dis.dispatch({ action: "open_room_settings" });
}}>
{ _t("Edit topic") }
</AccessibleButton> }
</div>,
hasCloseButton: true,
button: false,
});

defer(() => {
const topicNode = document.querySelector(".mx_jsTopicNode") as HTMLParagraphElement;
linkifyElement(topicNode);
});
}
});
useEffect(() => {
setTopic(getTopic(room));
}, [room]);

const ref = e => e && linkifyElement(e);
if (children) return children(topic, ref);
return <span ref={ref}>{ topic }</span>;
};
const className = classNames(props.className, "mx_RoomTopic");

export default RoomTopic;
return <div {...props}
ref={ref}
onClick={onClick}
dir="auto"
className={className}
>
{ topic }
{ hovered && (
<Tooltip label={_t("Click to read topic")} alignment={Alignment.Bottom} />
) }
</div>;
}
9 changes: 4 additions & 5 deletions src/components/views/rooms/RoomHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -186,11 +186,10 @@ export default class RoomHeader extends React.Component<IProps, IState> {
</ContextMenuTooltipButton>
);

const topicElement = <RoomTopic room={this.props.room}>
{ (topic, ref) => <div className="mx_RoomHeader_topic" ref={ref} title={topic} dir="auto">
{ topic }
</div> }
</RoomTopic>;
const topicElement = <RoomTopic
room={this.props.room}
className="mx_RoomHeader_topic"
/>;

let roomAvatar;
if (this.props.room) {
Expand Down
8 changes: 1 addition & 7 deletions src/components/views/rooms/RoomPreviewCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -182,13 +182,7 @@ const RoomPreviewCard: FC<IProps> = ({ room, onJoinButtonClicked, onRejectButton
<RoomName room={room} />
</h1>
<RoomInfoLine room={room} />
<RoomTopic room={room}>
{ (topic, ref) =>
topic ? <div className="mx_RoomPreviewCard_topic" ref={ref}>
{ topic }
</div> : null
}
</RoomTopic>
<RoomTopic room={room} className="mx_RoomPreviewCard_topic" />
{ room.getJoinRule() === "public" && <RoomFacePile room={room} /> }
{ notice ? <div className="mx_RoomPreviewCard_notice">
{ notice }
Expand Down
5 changes: 5 additions & 0 deletions src/dispatcher/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -312,4 +312,9 @@ export enum Action {
* Opens a dialog to add an existing object to a space. Used with a OpenAddExistingToSpaceDialogPayload.
*/
OpenAddToExistingSpaceDialog = "open_add_to_existing_space_dialog",

/**
* Show current room topic
*/
ShowRoomTopic = "show_room_topic"
}
2 changes: 2 additions & 0 deletions src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -2383,6 +2383,8 @@
"%(count)s members including %(commaSeparatedMembers)s|one": "%(commaSeparatedMembers)s",
"%(count)s people you know have already joined|other": "%(count)s people you know have already joined",
"%(count)s people you know have already joined|one": "%(count)s person you know has already joined",
"Edit topic": "Edit topic",
"Click to read topic": "Click to read topic",
"Server Options": "Server Options",
"You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use %(brand)s with an existing Matrix account on a different homeserver.": "You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use %(brand)s with an existing Matrix account on a different homeserver.",
"Join millions for free on the largest public server": "Join millions for free on the largest public server",
Expand Down

0 comments on commit 5b047a6

Please sign in to comment.