diff --git a/playwright/e2e/pinned-messages/index.ts b/playwright/e2e/pinned-messages/index.ts index 61e09a8111..ac50b62294 100644 --- a/playwright/e2e/pinned-messages/index.ts +++ b/playwright/e2e/pinned-messages/index.ts @@ -91,6 +91,14 @@ export class Helpers { await this.app.viewRoomByName(typeof room === "string" ? room : room.name); } + /** + * Get the timeline tile for the given message + * @param message + */ + getEventTile(message: string) { + return this.page.locator(".mx_EventTile", { hasText: message }); + } + /** * Pin the given message from the quick actions * @param message diff --git a/playwright/e2e/pinned-messages/pinned-messages.spec.ts b/playwright/e2e/pinned-messages/pinned-messages.spec.ts index f9d2abbb08..9f6f38f177 100644 --- a/playwright/e2e/pinned-messages/pinned-messages.spec.ts +++ b/playwright/e2e/pinned-messages/pinned-messages.spec.ts @@ -18,6 +18,22 @@ test.describe("Pinned messages", () => { await util.assertEmptyPinnedMessagesList(); }); + test("should pin one message and to have the pinned message badge in the timeline", async ({ + page, + app, + room1, + util, + }) => { + await util.goTo(room1); + await util.receiveMessages(room1, ["Msg1"]); + await util.pinMessages(["Msg1"]); + + const tile = util.getEventTile("Msg1"); + await expect(tile).toMatchScreenshot("pinned-message-Msg1.png", { + mask: [tile.locator(".mx_MessageTimestamp")], + }); + }); + test("should pin messages and show them in the room info panel", async ({ page, app, room1, util }) => { await util.goTo(room1); await util.receiveMessages(room1, ["Msg1", "Msg2", "Msg3", "Msg4"]); diff --git a/playwright/snapshots/pinned-messages/pinned-messages.spec.ts/pinned-message-Msg1-linux.png b/playwright/snapshots/pinned-messages/pinned-messages.spec.ts/pinned-message-Msg1-linux.png new file mode 100644 index 0000000000..c195186db8 Binary files /dev/null and b/playwright/snapshots/pinned-messages/pinned-messages.spec.ts/pinned-message-Msg1-linux.png differ diff --git a/res/css/_components.pcss b/res/css/_components.pcss index 78e0524da6..d62c63572a 100644 --- a/res/css/_components.pcss +++ b/res/css/_components.pcss @@ -249,6 +249,7 @@ @import "./views/messages/_MessageActionBar.pcss"; @import "./views/messages/_MessageTimestamp.pcss"; @import "./views/messages/_MjolnirBody.pcss"; +@import "./views/messages/_PinnedMessageBadge.pcss"; @import "./views/messages/_ReactionsRow.pcss"; @import "./views/messages/_ReactionsRowButton.pcss"; @import "./views/messages/_RedactedBody.pcss"; diff --git a/res/css/views/messages/_PinnedMessageBadge.pcss b/res/css/views/messages/_PinnedMessageBadge.pcss new file mode 100644 index 0000000000..99770a7037 --- /dev/null +++ b/res/css/views/messages/_PinnedMessageBadge.pcss @@ -0,0 +1,26 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only + * Please see LICENSE files in the repository root for full details. + * + */ + +.mx_PinnedMessageBadge { + position: relative; + display: flex; + align-items: center; + gap: var(--cpd-space-1x); + + padding: var(--cpd-space-1x) var(--cpd-space-3x) var(--cpd-space-1x) var(--cpd-space-1x); + font: var(--cpd-font-body-xs-medium); + background-color: var(--cpd-color-alpha-gray-200); + color: var(--cpd-color-text-secondary); + + border-radius: 99px; + border: 1px solid var(--cpd-color-alpha-gray-400); + + svg { + fill: var(--cpd-color-icon-secondary); + } +} diff --git a/res/css/views/messages/_ReactionsRow.pcss b/res/css/views/messages/_ReactionsRow.pcss index 3a820cfdc7..e07b529ef4 100644 --- a/res/css/views/messages/_ReactionsRow.pcss +++ b/res/css/views/messages/_ReactionsRow.pcss @@ -6,7 +6,6 @@ Please see LICENSE files in the repository root for full details. */ .mx_ReactionsRow { - margin: 6px 0; color: var(--cpd-color-text-primary); .mx_ReactionsRow_addReactionButton { diff --git a/res/css/views/rooms/_EventBubbleTile.pcss b/res/css/views/rooms/_EventBubbleTile.pcss index ec443c44de..3a42cde9bb 100644 --- a/res/css/views/rooms/_EventBubbleTile.pcss +++ b/res/css/views/rooms/_EventBubbleTile.pcss @@ -172,7 +172,8 @@ Please see LICENSE files in the repository root for full details. border-color: $quinary-content; } - .mx_ReactionsRow { + .mx_EventTile_footer { + margin: var(--cpd-space-1-5x) 0; margin-inline: var(--EventTile_bubble_line-margin-inline-start) var(--EventTile_bubble_line-margin-inline-end); } @@ -204,7 +205,8 @@ Please see LICENSE files in the repository root for full details. margin-inline-end: auto; } - .mx_ReactionsRow { + .mx_ReactionsRow, + .mx_EventTile_footer { justify-content: flex-start; } @@ -245,6 +247,10 @@ Please see LICENSE files in the repository root for full details. max-width: 100%; } + .mx_EventTile_footer { + justify-content: flex-end; + } + .mx_ReactionsRow { justify-content: flex-end; diff --git a/res/css/views/rooms/_EventTile.pcss b/res/css/views/rooms/_EventTile.pcss index e1bd304632..92e4cf78ea 100644 --- a/res/css/views/rooms/_EventTile.pcss +++ b/res/css/views/rooms/_EventTile.pcss @@ -463,6 +463,10 @@ $left-gutter: 64px; margin-left: calc(var(--name-width) + var(--icon-width) + 1 * var(--right-padding)); } } + + .mx_EventTile_footer { + margin: var(--cpd-space-1-5x) 0; + } } &[data-layout="group"] { @@ -509,8 +513,8 @@ $left-gutter: 64px; margin-left: $left-gutter; } - .mx_ReactionsRow { - margin: $spacing-4 64px; + .mx_EventTile_footer { + margin: var(--cpd-space-1x) var(--cpd-space-16x); } > .mx_DisambiguatedProfile { @@ -1248,7 +1252,7 @@ $left-gutter: 64px; padding-block-start: $spacing-16; .mx_EventTile_line, - .mx_ReactionsRow { + .mx_EventTile_footer { margin-inline-end: var(--ThreadView_group_spacing-end); } @@ -1266,7 +1270,7 @@ $left-gutter: 64px; } } - .mx_ReactionsRow { + .mx_EventTile_footer { /* Align with message text and summary text */ margin-inline-start: var(--ThreadView_group_spacing-start); } @@ -1456,6 +1460,12 @@ $left-gutter: 64px; display: flex; } +.mx_EventTile_footer { + display: flex; + gap: var(--cpd-space-2x); + align-items: center; +} + /* Media query for mobile UI */ @media only screen and (max-width: 480px) { .mx_EventTile_content { diff --git a/src/components/views/messages/PinnedMessageBadge.tsx b/src/components/views/messages/PinnedMessageBadge.tsx new file mode 100644 index 0000000000..bfe1919597 --- /dev/null +++ b/src/components/views/messages/PinnedMessageBadge.tsx @@ -0,0 +1,24 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only + * Please see LICENSE files in the repository root for full details. + * + */ + +import React, { JSX } from "react"; +import { Icon as PinIcon } from "@vector-im/compound-design-tokens/icons/pin-solid.svg"; + +import { _t } from "../../../languageHandler.tsx"; + +/** + * A badge to indicate that a message is pinned. + */ +export function PinnedMessageBadge(): JSX.Element { + return ( +