diff --git a/res/css/structures/_FilePanel.scss b/res/css/structures/_FilePanel.scss index 21b30d804a..2aa068b674 100644 --- a/res/css/structures/_FilePanel.scss +++ b/res/css/structures/_FilePanel.scss @@ -23,6 +23,13 @@ limitations under the License. .mx_FilePanel .mx_RoomView_messageListWrapper { margin-right: 20px; + flex-direction: row; + align-items: center; + justify-content: center; +} + +.mx_FilePanel .mx_RoomView_MessageList { + width: 100%; } .mx_FilePanel .mx_RoomView_MessageList h2 { diff --git a/res/css/structures/_NotificationPanel.scss b/res/css/structures/_NotificationPanel.scss index 715a94fe2c..1258ace069 100644 --- a/res/css/structures/_NotificationPanel.scss +++ b/res/css/structures/_NotificationPanel.scss @@ -22,7 +22,13 @@ limitations under the License. } .mx_NotificationPanel .mx_RoomView_messageListWrapper { - margin-right: 20px; + flex-direction: row; + align-items: center; + justify-content: center; +} + +.mx_NotificationPanel .mx_RoomView_MessageList { + width: 100%; } .mx_NotificationPanel .mx_RoomView_MessageList h2 { @@ -35,11 +41,32 @@ limitations under the License. .mx_NotificationPanel .mx_EventTile { word-break: break-word; + position: relative; + padding-bottom: 18px; + + &:not(.mx_EventTile_last):not(.mx_EventTile_lastInSection)::after { + position: absolute; + bottom: 0; + left: 0; + right: 0; + background-color: $tertiary-fg-color; + height: 1px; + opacity: 0.4; + content: ''; + } } .mx_NotificationPanel .mx_EventTile_roomName { font-weight: bold; font-size: $font-14px; + + > * { + vertical-align: middle; + } + + > .mx_BaseAvatar { + margin-right: 8px; + } } .mx_NotificationPanel .mx_EventTile_roomName a { @@ -47,8 +74,7 @@ limitations under the License. } .mx_NotificationPanel .mx_EventTile_avatar { - top: 8px; - left: 0px; + display: none; // we don't need this in this view } .mx_NotificationPanel .mx_EventTile .mx_SenderProfile, @@ -60,8 +86,7 @@ limitations under the License. } .mx_NotificationPanel .mx_EventTile_senderDetails { - padding-left: 32px; - padding-top: 8px; + padding-left: 36px; // align with the room name position: relative; a { @@ -82,7 +107,7 @@ limitations under the License. .mx_NotificationPanel .mx_EventTile_line { margin-right: 0px; - padding-left: 32px; + padding-left: 36px; // align with the room name padding-top: 0px; padding-bottom: 0px; padding-right: 0px; diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index 3b60c4e62b..572c7166d2 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -185,13 +185,11 @@ limitations under the License. } .mx_RoomView_empty { - flex: 1 1 auto; font-size: $font-13px; - padding-left: 3em; - padding-right: 3em; - margin-right: 20px; - margin-top: 33%; + padding: 0 24px; + margin-right: 30px; text-align: center; + margin-bottom: 80px; // visually center the content (intentional offset) } .mx_RoomView_MessageList { diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js index fe7b20a2d9..e2e3592536 100644 --- a/src/components/structures/MessagePanel.js +++ b/src/components/structures/MessagePanel.js @@ -518,10 +518,13 @@ export default class MessagePanel extends React.Component { if (!grouper) { const wantTile = this._shouldShowEvent(mxEv); if (wantTile) { + const nextEvent = i < this.props.events.length - 1 + ? this.props.events[i + 1] + : null; // make sure we unpack the array returned by _getTilesForEvent, // otherwise react will auto-generate keys and we will end up // replacing all of the DOM elements every time we paginate. - ret.push(...this._getTilesForEvent(prevEvent, mxEv, last)); + ret.push(...this._getTilesForEvent(prevEvent, mxEv, last, nextEvent)); prevEvent = mxEv; } @@ -537,7 +540,7 @@ export default class MessagePanel extends React.Component { return ret; } - _getTilesForEvent(prevEvent, mxEv, last) { + _getTilesForEvent(prevEvent, mxEv, last, nextEvent) { const TileErrorBoundary = sdk.getComponent('messages.TileErrorBoundary'); const EventTile = sdk.getComponent('rooms.EventTile'); const DateSeparator = sdk.getComponent('messages.DateSeparator'); @@ -562,6 +565,11 @@ export default class MessagePanel extends React.Component { ret.push(dateSeparator); } + let willWantDateSeparator = false; + if (nextEvent) { + willWantDateSeparator = this._wantsDateSeparator(mxEv, nextEvent.getDate() || new Date()); + } + // is this a continuation of the previous message? const continuation = !wantsDateSeparator && shouldFormContinuation(prevEvent, mxEv); @@ -598,6 +606,7 @@ export default class MessagePanel extends React.Component { isTwelveHour={this.props.isTwelveHour} permalinkCreator={this.props.permalinkCreator} last={last} + lastInSection={willWantDateSeparator} isSelectedEvent={highlight} getRelationsForEvent={this.props.getRelationsForEvent} showReactions={this.props.showReactions} diff --git a/src/components/views/rooms/EventTile.js b/src/components/views/rooms/EventTile.js index f444fb1f1a..a1cc681a4c 100644 --- a/src/components/views/rooms/EventTile.js +++ b/src/components/views/rooms/EventTile.js @@ -34,6 +34,7 @@ import * as ObjectUtils from "../../../ObjectUtils"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; import {E2E_STATE} from "./E2EIcon"; import {toRem} from "../../../utils/units"; +import RoomAvatar from "../avatars/RoomAvatar"; const eventTileTypes = { 'm.room.message': 'messages.MessageEvent', @@ -147,6 +148,10 @@ export default class EventTile extends React.Component { */ last: PropTypes.bool, + // true if the event is the last event in a section (adds a css class for + // targeting) + lastInSection: PropTypes.bool, + /* true if this is search context (which has the effect of greying out * the text */ @@ -673,6 +678,7 @@ export default class EventTile extends React.Component { mx_EventTile_selected: this.props.isSelectedEvent, mx_EventTile_continuation: this.props.tileShape ? '' : this.props.continuation, mx_EventTile_last: this.props.last, + mx_EventTile_lastInSection: this.props.lastInSection, mx_EventTile_contextual: this.props.contextual, mx_EventTile_actionBarFocused: this.state.actionBarFocused, mx_EventTile_verified: !isBubbleMessage && this.state.verified === E2E_STATE.VERIFIED, @@ -821,6 +827,7 @@ export default class EventTile extends React.Component { return (