Fix baseline misalignment of thread panel summary by deduplication (#8413)
This commit is contained in:
parent
5a5a792593
commit
8baa46b0dd
10 changed files with 147 additions and 143 deletions
|
@ -263,6 +263,7 @@
|
|||
@import "./views/rooms/_SearchBar.scss";
|
||||
@import "./views/rooms/_SendMessageComposer.scss";
|
||||
@import "./views/rooms/_Stickers.scss";
|
||||
@import "./views/rooms/_ThreadSummary.scss";
|
||||
@import "./views/rooms/_TopUnreadMessagesBar.scss";
|
||||
@import "./views/rooms/_VoiceRecordComposerTile.scss";
|
||||
@import "./views/rooms/_WhoIsTypingTile.scss";
|
||||
|
|
|
@ -140,7 +140,7 @@ limitations under the License.
|
|||
// Account for scrollbar when hovering
|
||||
padding-top: 0;
|
||||
|
||||
.mx_ThreadInfo {
|
||||
.mx_ThreadSummary {
|
||||
position: relative;
|
||||
padding-right: 11px;
|
||||
|
||||
|
@ -257,28 +257,14 @@ limitations under the License.
|
|||
|
||||
.mx_ThreadPanel_replies {
|
||||
margin-top: 8px;
|
||||
}
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
|
||||
.mx_ThreadPanel_repliesSummary {
|
||||
&::before {
|
||||
content: "";
|
||||
mask-image: url('$(res)/img/element-icons/thread-summary.svg');
|
||||
mask-position: center;
|
||||
display: inline-block;
|
||||
height: 18px;
|
||||
min-width: 18px;
|
||||
background-color: currentColor;
|
||||
mask-repeat: no-repeat;
|
||||
mask-size: contain;
|
||||
margin-right: 8px;
|
||||
vertical-align: middle;
|
||||
.mx_ThreadSummary_threads-amount {
|
||||
color: $secondary-content;
|
||||
font-size: $font-12px;
|
||||
}
|
||||
|
||||
color: $secondary-content;
|
||||
font-weight: 600;
|
||||
float: left;
|
||||
margin-right: 12px;
|
||||
font-size: $font-12px;
|
||||
}
|
||||
|
||||
.mx_ThreadPanel_viewInRoom::before {
|
||||
|
|
|
@ -69,7 +69,7 @@ limitations under the License.
|
|||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.mx_ThreadInfo {
|
||||
.mx_ThreadSummary {
|
||||
margin-left: 36px;
|
||||
margin-right: 0;
|
||||
max-width: min(calc(100% - 36px), 600px);
|
||||
|
|
|
@ -37,7 +37,7 @@ limitations under the License.
|
|||
margin-left: 49px;
|
||||
font-size: $font-14px;
|
||||
|
||||
.mx_ThreadInfo {
|
||||
.mx_ThreadSummary {
|
||||
clear: both;
|
||||
width: fit-content;
|
||||
}
|
||||
|
@ -172,7 +172,7 @@ limitations under the License.
|
|||
margin-right: 32px;
|
||||
}
|
||||
|
||||
.mx_ThreadInfo {
|
||||
.mx_ThreadSummary {
|
||||
float: right;
|
||||
margin-right: calc(-1 * var(--gutterSize));
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ $left-gutter: 64px;
|
|||
background-color: $alert;
|
||||
}
|
||||
|
||||
.mx_ThreadInfo,
|
||||
.mx_ThreadSummary,
|
||||
.mx_ThreadSummaryIcon {
|
||||
margin-left: 64px;
|
||||
}
|
||||
|
@ -304,7 +304,7 @@ $left-gutter: 64px;
|
|||
.mx_RoomView_timeline_rr_enabled {
|
||||
.mx_EventTile[data-layout=group] {
|
||||
|
||||
.mx_ThreadInfo,
|
||||
.mx_ThreadSummary,
|
||||
.mx_ThreadSummaryIcon,
|
||||
.mx_EventTile_line {
|
||||
/* ideally should be 100px, but 95px gives us a max thumbnail size of 800x600, which is nice */
|
||||
|
@ -312,7 +312,7 @@ $left-gutter: 64px;
|
|||
min-height: $font-14px;
|
||||
}
|
||||
|
||||
.mx_ThreadInfo {
|
||||
.mx_ThreadSummary {
|
||||
max-width: min(calc(100% - $left-gutter - 110px), 600px); // leave space on both left & right gutters
|
||||
}
|
||||
}
|
||||
|
@ -680,8 +680,9 @@ $left-gutter: 64px;
|
|||
}
|
||||
}
|
||||
|
||||
.mx_ThreadPanel_replies::before,
|
||||
.mx_ThreadSummaryIcon::before,
|
||||
.mx_ThreadInfo::before {
|
||||
.mx_ThreadSummary::before {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
mask-image: url('$(res)/img/element-icons/thread-summary.svg');
|
||||
|
@ -707,113 +708,12 @@ $left-gutter: 64px;
|
|||
}
|
||||
}
|
||||
|
||||
.mx_ThreadInfo {
|
||||
min-width: 267px;
|
||||
max-width: min(calc(100% - $left-gutter), 600px); // leave space on both left & right gutters
|
||||
width: fit-content;
|
||||
height: 40px;
|
||||
position: relative;
|
||||
background-color: $system;
|
||||
padding-left: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 8px;
|
||||
padding-right: 16px;
|
||||
margin-top: 8px;
|
||||
font-size: $font-12px;
|
||||
color: $secondary-content;
|
||||
box-sizing: border-box;
|
||||
justify-content: flex-start;
|
||||
clear: both;
|
||||
overflow: hidden;
|
||||
border: 1px solid $system; // always render a border so the hover effect doesn't require a re-layout
|
||||
|
||||
.mx_ThreadInfo_chevron {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 60px;
|
||||
box-sizing: border-box;
|
||||
// XXX: We use `$system-transparent` instead of `transparent` to work around a Safari <15.4 bug
|
||||
background: linear-gradient(270deg, $system 50%, $system-transparent 100%);
|
||||
|
||||
opacity: 0;
|
||||
transform: translateX(60px);
|
||||
transition: all .1s ease-in-out;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 12px;
|
||||
transform: translateY(-50%);
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
mask-image: url('$(res)/img/compound/chevron-right-12px.svg');
|
||||
mask-position: center;
|
||||
mask-size: contain;
|
||||
mask-repeat: no-repeat;
|
||||
background-color: $secondary-content;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
cursor: pointer;
|
||||
border-color: $quinary-content;
|
||||
|
||||
.mx_ThreadInfo_chevron {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
&::before {
|
||||
align-self: center; // v-align the threads icon
|
||||
}
|
||||
}
|
||||
|
||||
.mx_MessagePanel_narrow .mx_ThreadInfo {
|
||||
.mx_MessagePanel_narrow .mx_ThreadSummary {
|
||||
min-width: initial;
|
||||
max-width: initial;
|
||||
width: initial;
|
||||
}
|
||||
|
||||
$threadInfoLineHeight: calc(2 * $font-12px);
|
||||
|
||||
.mx_ThreadInfo_sender {
|
||||
font-weight: $font-semi-bold;
|
||||
line-height: $threadInfoLineHeight;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.mx_ThreadInfo_content {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
margin-left: 4px;
|
||||
font-size: $font-12px;
|
||||
line-height: $threadInfoLineHeight;
|
||||
color: $secondary-content;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.mx_ThreadInfo_avatar {
|
||||
float: left;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.mx_ThreadInfo_threads-amount {
|
||||
font-weight: $font-semi-bold;
|
||||
position: relative;
|
||||
padding: 0 12px 0 8px;
|
||||
white-space: nowrap;
|
||||
line-height: $threadInfoLineHeight;
|
||||
}
|
||||
|
||||
.mx_EventTile[data-shape=ThreadsList] {
|
||||
--topOffset: 20px;
|
||||
--leftOffset: 46px;
|
||||
|
|
|
@ -40,7 +40,7 @@ $irc-line-height: $font-18px;
|
|||
margin-right: $right-padding;
|
||||
}
|
||||
|
||||
.mx_ThreadInfo {
|
||||
.mx_ThreadSummary {
|
||||
margin-right: 0;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
|
117
res/css/views/rooms/_ThreadSummary.scss
Normal file
117
res/css/views/rooms/_ThreadSummary.scss
Normal file
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
Copyright 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.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
$left-gutter: 64px; // From _EventTile.scss
|
||||
$threadSummaryLineHeight: calc(2 * $font-12px);
|
||||
|
||||
.mx_ThreadSummary {
|
||||
min-width: 267px;
|
||||
max-width: min(calc(100% - $left-gutter), 600px); // leave space on both left & right gutters
|
||||
width: fit-content;
|
||||
height: 40px;
|
||||
position: relative;
|
||||
background-color: $system;
|
||||
padding-left: $spacing-12;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 8px;
|
||||
padding-right: $spacing-16;
|
||||
margin-top: $spacing-8;
|
||||
font-size: $font-12px;
|
||||
color: $secondary-content;
|
||||
box-sizing: border-box;
|
||||
justify-content: flex-start;
|
||||
clear: both;
|
||||
overflow: hidden;
|
||||
border: 1px solid $system; // always render a border so the hover effect doesn't require a re-layout
|
||||
|
||||
.mx_ThreadSummary_chevron {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 60px;
|
||||
box-sizing: border-box;
|
||||
// XXX: We use `$system-transparent` instead of `transparent` to work around a Safari <15.4 bug
|
||||
background: linear-gradient(270deg, $system 50%, $system-transparent 100%);
|
||||
|
||||
opacity: 0;
|
||||
transform: translateX(60px);
|
||||
transition: all .1s ease-in-out;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: $spacing-12;
|
||||
transform: translateY(-50%);
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
mask-image: url('$(res)/img/compound/chevron-right-12px.svg');
|
||||
mask-position: center;
|
||||
mask-size: contain;
|
||||
mask-repeat: no-repeat;
|
||||
background-color: $secondary-content;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
cursor: pointer;
|
||||
border-color: $quinary-content;
|
||||
|
||||
.mx_ThreadSummary_chevron {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
&::before {
|
||||
align-self: center; // v-align the threads icon
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: these classes are re-used outside of the component
|
||||
.mx_ThreadSummary_threads-amount {
|
||||
font-weight: $font-semi-bold;
|
||||
position: relative;
|
||||
padding: 0 $spacing-12 0 $spacing-8;
|
||||
white-space: nowrap;
|
||||
line-height: $threadSummaryLineHeight;
|
||||
}
|
||||
|
||||
.mx_ThreadSummary_sender {
|
||||
font-weight: $font-semi-bold;
|
||||
line-height: $threadSummaryLineHeight;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.mx_ThreadSummary_content {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
margin-left: $spacing-4;
|
||||
font-size: $font-12px;
|
||||
line-height: $threadSummaryLineHeight;
|
||||
color: $secondary-content;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.mx_ThreadSummary_avatar {
|
||||
margin-right: $spacing-8;
|
||||
}
|
|
@ -517,7 +517,7 @@ export class UnwrappedEventTile extends React.Component<IProps, IState> {
|
|||
}
|
||||
|
||||
return <div className="mx_ThreadPanel_replies">
|
||||
<span className="mx_ThreadPanel_repliesSummary">
|
||||
<span className="mx_ThreadSummary_threads-amount">
|
||||
{ this.state.thread.length }
|
||||
</span>
|
||||
<ThreadMessagePreview thread={this.state.thread} />
|
||||
|
|
|
@ -48,7 +48,7 @@ const ThreadSummary = ({ mxEvent, thread }: IProps) => {
|
|||
|
||||
return (
|
||||
<AccessibleButton
|
||||
className="mx_ThreadInfo"
|
||||
className="mx_ThreadSummary"
|
||||
onClick={(ev: ButtonEvent) => {
|
||||
showThread({
|
||||
rootEvent: mxEvent,
|
||||
|
@ -58,11 +58,11 @@ const ThreadSummary = ({ mxEvent, thread }: IProps) => {
|
|||
}}
|
||||
aria-label={_t("Open thread")}
|
||||
>
|
||||
<span className="mx_ThreadInfo_threads-amount">
|
||||
<span className="mx_ThreadSummary_threads-amount">
|
||||
{ countSection }
|
||||
</span>
|
||||
<ThreadMessagePreview thread={thread} showDisplayname={!roomContext.narrow} />
|
||||
<div className="mx_ThreadInfo_chevron" />
|
||||
<div className="mx_ThreadSummary_chevron" />
|
||||
</AccessibleButton>
|
||||
);
|
||||
};
|
||||
|
@ -96,13 +96,13 @@ export const ThreadMessagePreview = ({ thread, showDisplayname = false }: IPrevi
|
|||
fallbackUserId={lastReply.getSender()}
|
||||
width={24}
|
||||
height={24}
|
||||
className="mx_ThreadInfo_avatar"
|
||||
className="mx_ThreadSummary_avatar"
|
||||
/>
|
||||
{ showDisplayname && <div className="mx_ThreadInfo_sender">
|
||||
{ showDisplayname && <div className="mx_ThreadSummary_sender">
|
||||
{ lastReply.sender?.name ?? lastReply.getSender() }
|
||||
</div> }
|
||||
<div className="mx_ThreadInfo_content">
|
||||
<span className="mx_ThreadInfo_message-preview">
|
||||
<div className="mx_ThreadSummary_content">
|
||||
<span className="mx_ThreadSummary_message-preview">
|
||||
{ preview }
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
@ -137,17 +137,17 @@ export async function assertTimelineThreadSummary(
|
|||
content: string,
|
||||
): Promise<void> {
|
||||
session.log.step("asserts the timeline thread summary is as expected");
|
||||
const summaries = await session.queryAll(".mx_MainSplit_timeline .mx_ThreadInfo");
|
||||
const summaries = await session.queryAll(".mx_MainSplit_timeline .mx_ThreadSummary");
|
||||
const summary = summaries[summaries.length - 1];
|
||||
assert.equal(await session.innerText(await summary.$(".mx_ThreadInfo_sender")), sender);
|
||||
assert.equal(await session.innerText(await summary.$(".mx_ThreadInfo_content")), content);
|
||||
assert.equal(await session.innerText(await summary.$(".mx_ThreadSummary_sender")), sender);
|
||||
assert.equal(await session.innerText(await summary.$(".mx_ThreadSummary_content")), content);
|
||||
session.log.done();
|
||||
}
|
||||
|
||||
export async function clickTimelineThreadSummary(session: ElementSession): Promise<void> {
|
||||
session.log.step(`clicks the latest thread summary in the timeline`);
|
||||
|
||||
const summaries = await session.queryAll(".mx_MainSplit_timeline .mx_ThreadInfo");
|
||||
const summaries = await session.queryAll(".mx_MainSplit_timeline .mx_ThreadSummary");
|
||||
await summaries[summaries.length - 1].click();
|
||||
|
||||
session.log.done();
|
||||
|
|
Loading…
Reference in a new issue