diff --git a/apps/web/res/css/_components.pcss b/apps/web/res/css/_components.pcss index 339c4fd37c..f775cd1698 100644 --- a/apps/web/res/css/_components.pcss +++ b/apps/web/res/css/_components.pcss @@ -236,7 +236,6 @@ @import "./views/messages/_MediaBody.pcss"; @import "./views/messages/_MessageActionBar.pcss"; @import "./views/messages/_MjolnirBody.pcss"; -@import "./views/messages/_PinnedMessageBadge.pcss"; @import "./views/messages/_ReactionsRow.pcss"; @import "./views/messages/_RedactedBody.pcss"; @import "./views/messages/_RoomAvatarEvent.pcss"; diff --git a/apps/web/src/components/views/messages/PinnedMessageBadge.tsx b/apps/web/src/components/views/messages/PinnedMessageBadge.tsx deleted file mode 100644 index 373e577f63..0000000000 --- a/apps/web/src/components/views/messages/PinnedMessageBadge.tsx +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2024 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial - * Please see LICENSE files in the repository root for full details. - */ - -import React, { type HTMLProps, type JSX } from "react"; -import PinIcon from "@vector-im/compound-design-tokens/assets/web/icons/pin-solid"; - -import { _t } from "../../../languageHandler"; - -/** - * A badge to indicate that a message is pinned. - */ -export function PinnedMessageBadge(props: Readonly>): JSX.Element { - return ( -
- - {_t("room|pinned_message_badge")} -
- ); -} diff --git a/apps/web/src/components/views/rooms/EventTile.tsx b/apps/web/src/components/views/rooms/EventTile.tsx index af35f2c800..72ba6dcf95 100644 --- a/apps/web/src/components/views/rooms/EventTile.tsx +++ b/apps/web/src/components/views/rooms/EventTile.tsx @@ -52,6 +52,7 @@ import { useCreateAutoDisposedViewModel, DecryptionFailureBodyView, MessageTimestampView, + PinnedMessageBadge, ReactionsRowButtonView, ReactionsRowView, useViewModel, @@ -102,7 +103,6 @@ import { EventTileThreadToolbar } from "./EventTile/EventTileThreadToolbar"; import { getLateEventInfo } from "../../structures/grouper/LateEventGrouper"; import { Icon as LateIcon } from "../../../../res/img/sensor.svg"; import PinningUtils from "../../../utils/PinningUtils"; -import { PinnedMessageBadge } from "../messages/PinnedMessageBadge"; import { EventPreview } from "./EventPreview"; import { ElementCallEventType } from "../../../call-types"; import { DecryptionFailureBodyViewModel } from "../../../viewmodels/message-body/DecryptionFailureBodyViewModel"; diff --git a/apps/web/src/i18n/strings/en_EN.json b/apps/web/src/i18n/strings/en_EN.json index fe5e15e54e..75f323a920 100644 --- a/apps/web/src/i18n/strings/en_EN.json +++ b/apps/web/src/i18n/strings/en_EN.json @@ -2088,7 +2088,6 @@ "not_found_title": "This room or space does not exist.", "not_found_title_name": "%(roomName)s does not exist.", "peek_join_prompt": "You're previewing %(roomName)s. Want to join it?", - "pinned_message_badge": "Pinned message", "pinned_message_banner": { "button_close_list": "Close list", "button_view_all": "View all", diff --git a/apps/web/test/unit-tests/components/views/messages/PinnedMessageBadge-test.tsx b/apps/web/test/unit-tests/components/views/messages/PinnedMessageBadge-test.tsx deleted file mode 100644 index 884a78fd6c..0000000000 --- a/apps/web/test/unit-tests/components/views/messages/PinnedMessageBadge-test.tsx +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright 2024 New Vector Ltd. - * - * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial - * Please see LICENSE files in the repository root for full details. - */ - -import React from "react"; -import { render } from "jest-matrix-react"; - -import { PinnedMessageBadge } from "../../../../../src/components/views/messages/PinnedMessageBadge.tsx"; - -describe("PinnedMessageBadge", () => { - it("should render", () => { - const { asFragment } = render(); - expect(asFragment()).toMatchSnapshot(); - }); -}); diff --git a/packages/shared-components/__vis__/linux/__baselines__/message-body/PinnedMessageBadge/PinnedMessageBadge.stories.tsx/default-auto.png b/packages/shared-components/__vis__/linux/__baselines__/message-body/PinnedMessageBadge/PinnedMessageBadge.stories.tsx/default-auto.png new file mode 100644 index 0000000000..5ad54ca745 Binary files /dev/null and b/packages/shared-components/__vis__/linux/__baselines__/message-body/PinnedMessageBadge/PinnedMessageBadge.stories.tsx/default-auto.png differ diff --git a/packages/shared-components/src/i18n/strings/en_EN.json b/packages/shared-components/src/i18n/strings/en_EN.json index 06a51d1690..1a1dc79ccd 100644 --- a/packages/shared-components/src/i18n/strings/en_EN.json +++ b/packages/shared-components/src/i18n/strings/en_EN.json @@ -47,6 +47,7 @@ "jump_to_date": "Jump to date", "jump_to_date_beginning": "The beginning of the room", "jump_to_date_prompt": "Pick a date to jump to", + "pinned_message_badge": "Pinned message", "status_bar": { "delete_all": "Delete all", "exceeded_resource_limit_description": "Please contact your service administrator to continue using the service.", diff --git a/packages/shared-components/src/index.ts b/packages/shared-components/src/index.ts index aff3b98ceb..15d5cc39f8 100644 --- a/packages/shared-components/src/index.ts +++ b/packages/shared-components/src/index.ts @@ -20,6 +20,7 @@ export * from "./message-body/EventContentBody"; export * from "./message-body/MediaBody"; export * from "./message-body/MessageTimestampView"; export * from "./message-body/DecryptionFailureBodyView"; +export * from "./message-body/PinnedMessageBadge"; export * from "./message-body/ReactionsRowButtonTooltip"; export * from "./message-body/ReactionsRowButton"; export * from "./message-body/ReactionsRow"; diff --git a/apps/web/res/css/views/messages/_PinnedMessageBadge.pcss b/packages/shared-components/src/message-body/PinnedMessageBadge/PinnedMessageBadge.module.css similarity index 91% rename from apps/web/res/css/views/messages/_PinnedMessageBadge.pcss rename to packages/shared-components/src/message-body/PinnedMessageBadge/PinnedMessageBadge.module.css index 722945a49c..cee0c3feaf 100644 --- a/apps/web/res/css/views/messages/_PinnedMessageBadge.pcss +++ b/packages/shared-components/src/message-body/PinnedMessageBadge/PinnedMessageBadge.module.css @@ -1,23 +1,21 @@ /* - * Copyright 2024 New Vector Ltd. + * Copyright 2026 Element Creations Ltd. * * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial * Please see LICENSE files in the repository root for full details. */ -.mx_PinnedMessageBadge { +.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-bg-subtle-secondary); color: var(--cpd-color-text-secondary); - - border-radius: 99px; border: 1px solid var(--cpd-color-alpha-gray-400); + border-radius: 99px; svg { fill: var(--cpd-color-icon-secondary); diff --git a/packages/shared-components/src/message-body/PinnedMessageBadge/PinnedMessageBadge.stories.tsx b/packages/shared-components/src/message-body/PinnedMessageBadge/PinnedMessageBadge.stories.tsx new file mode 100644 index 0000000000..fb073069a6 --- /dev/null +++ b/packages/shared-components/src/message-body/PinnedMessageBadge/PinnedMessageBadge.stories.tsx @@ -0,0 +1,25 @@ +/* + * Copyright 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +import type { Meta, StoryObj } from "@storybook/react-vite"; +import { PinnedMessageBadge } from "./PinnedMessageBadge"; + +const meta = { + title: "Message body/PinnedMessageBadge", + component: PinnedMessageBadge, + args: { + "aria-describedby": "event-tile-description", + "tabIndex": 0, + }, + tags: ["autodocs"], +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/packages/shared-components/src/message-body/PinnedMessageBadge/PinnedMessageBadge.test.tsx b/packages/shared-components/src/message-body/PinnedMessageBadge/PinnedMessageBadge.test.tsx new file mode 100644 index 0000000000..a2d74a6b9c --- /dev/null +++ b/packages/shared-components/src/message-body/PinnedMessageBadge/PinnedMessageBadge.test.tsx @@ -0,0 +1,22 @@ +/* + * Copyright 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +import React from "react"; +import { composeStories } from "@storybook/react-vite"; +import { describe, expect, it } from "vitest"; +import { render } from "@test-utils"; + +import * as stories from "./PinnedMessageBadge.stories"; + +const { Default } = composeStories(stories); + +describe("PinnedMessageBadge", () => { + it("renders the default badge", () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/packages/shared-components/src/message-body/PinnedMessageBadge/PinnedMessageBadge.tsx b/packages/shared-components/src/message-body/PinnedMessageBadge/PinnedMessageBadge.tsx new file mode 100644 index 0000000000..5d16397306 --- /dev/null +++ b/packages/shared-components/src/message-body/PinnedMessageBadge/PinnedMessageBadge.tsx @@ -0,0 +1,27 @@ +/* + * Copyright 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +import React, { type HTMLAttributes, type JSX } from "react"; +import classNames from "classnames"; +import PinIcon from "@vector-im/compound-design-tokens/assets/web/icons/pin-solid"; + +import styles from "./PinnedMessageBadge.module.css"; +import { _t } from "../../utils/i18n"; + +export type PinnedMessageBadgeProps = HTMLAttributes; + +/** + * A badge indicating that a message is pinned. + */ +export function PinnedMessageBadge({ className, children, ...props }: Readonly): JSX.Element { + return ( +
+ + {children ?? _t("room|pinned_message_badge")} +
+ ); +} diff --git a/apps/web/test/unit-tests/components/views/messages/__snapshots__/PinnedMessageBadge-test.tsx.snap b/packages/shared-components/src/message-body/PinnedMessageBadge/__snapshots__/PinnedMessageBadge.test.tsx.snap similarity index 69% rename from apps/web/test/unit-tests/components/views/messages/__snapshots__/PinnedMessageBadge-test.tsx.snap rename to packages/shared-components/src/message-body/PinnedMessageBadge/__snapshots__/PinnedMessageBadge.test.tsx.snap index dd321a1c16..58e9a90e5f 100644 --- a/apps/web/test/unit-tests/components/views/messages/__snapshots__/PinnedMessageBadge-test.tsx.snap +++ b/packages/shared-components/src/message-body/PinnedMessageBadge/__snapshots__/PinnedMessageBadge.test.tsx.snap @@ -1,9 +1,11 @@ -// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`PinnedMessageBadge should render 1`] = ` - +exports[`PinnedMessageBadge > renders the default badge 1`] = ` +
Pinned message
- +
`; diff --git a/packages/shared-components/src/message-body/PinnedMessageBadge/index.tsx b/packages/shared-components/src/message-body/PinnedMessageBadge/index.tsx new file mode 100644 index 0000000000..5e74f31a57 --- /dev/null +++ b/packages/shared-components/src/message-body/PinnedMessageBadge/index.tsx @@ -0,0 +1,8 @@ +/* + * Copyright 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +export { PinnedMessageBadge, type PinnedMessageBadgeProps } from "./PinnedMessageBadge"; diff --git a/packages/shared-components/vitest.config.ts b/packages/shared-components/vitest.config.ts index 7b0f22f9e0..b28a1718e3 100644 --- a/packages/shared-components/vitest.config.ts +++ b/packages/shared-components/vitest.config.ts @@ -153,7 +153,11 @@ export default defineConfig({ ], }, optimizeDeps: { - include: ["vite-plugin-node-polyfills/shims/buffer", "vite-plugin-node-polyfills/shims/process"], + include: [ + "vite-plugin-node-polyfills/shims/buffer", + "vite-plugin-node-polyfills/shims/process", + "react-virtuoso", + ], }, resolve: { alias: {