From 2581ff81370cd64af43c9382e2797533ef5dbe20 Mon Sep 17 00:00:00 2001 From: heaven Date: Sat, 6 Jun 2026 21:13:34 +0300 Subject: [PATCH] feat(room): extend the centred message band, date pill and composer width to group and channel rooms, matching 1:1 --- .../components/message/layout/Channel.css.ts | 39 +++------------- src/app/components/message/layout/Channel.tsx | 23 ---------- src/app/features/room/RoomTimeline.css.ts | 6 ++- src/app/features/room/RoomTimeline.tsx | 45 ++++++++----------- src/app/features/room/RoomView.css.ts | 21 +++------ src/app/features/room/RoomView.tsx | 34 ++++---------- 6 files changed, 42 insertions(+), 126 deletions(-) diff --git a/src/app/components/message/layout/Channel.css.ts b/src/app/components/message/layout/Channel.css.ts index 2958b567..85776a32 100644 --- a/src/app/components/message/layout/Channel.css.ts +++ b/src/app/components/message/layout/Channel.css.ts @@ -16,10 +16,12 @@ export const ChannelRow = style({ display: 'flex', alignItems: 'flex-start', gap: ChannelAvatarGap, - // Span the full pane edge-to-edge so the hover highlight runs the whole - // width like Discord: cancel MessageBase's S400/S200 horizontal padding with - // negative margins, then re-add the 16px avatar gutter as paddingLeft (so the - // avatar's left edge lands exactly 16px from the screen edge — Discord cozy). + // Span the full message-column width so the hover highlight runs edge-to-edge + // like Discord: cancel MessageBase's S400/S200 horizontal padding with negative + // margins, then re-add the 16px avatar gutter as paddingLeft (so the avatar's + // left edge lands 16px from the column edge — Discord cozy). NB: the column is + // the centred BubbleTimelineBand, so that edge is the band's content edge, not + // the screen edge (the band adds 12px native / 40px desktop outside this). marginLeft: `calc(-1 * ${config.space.S400})`, marginRight: `calc(-1 * ${config.space.S200})`, paddingLeft: ChannelEdgePad, @@ -82,35 +84,6 @@ export const ChannelThreadSummary = style({ marginTop: config.space.S100, }); -// Horizontal line + centered label. Spans the full row width including -// the avatar slot so the line reads as a section break, not a per-message -// chrome element. -export const ChannelDayDividerRoot = style({ - display: 'flex', - alignItems: 'center', - gap: config.space.S300, - paddingLeft: config.space.S400, - paddingRight: config.space.S400, - paddingTop: config.space.S400, - paddingBottom: config.space.S400, -}); - -export const ChannelDayDividerLine = style({ - flex: 1, - height: '1px', - backgroundColor: color.SurfaceVariant.ContainerLine, -}); - -export const ChannelDayDividerLabel = style({ - fontSize: toRem(11), - fontWeight: 600, - letterSpacing: '0.06em', - textTransform: 'uppercase', - color: color.SurfaceVariant.OnContainer, - opacity: 0.7, - flexShrink: 0, -}); - // Sysline (membership / room.create / pinned-events). Compact single // row aligned with the body gutter — the sysline sits where messages' // body would, indented past the avatar slot, so the column reads diff --git a/src/app/components/message/layout/Channel.tsx b/src/app/components/message/layout/Channel.tsx index 98b17c0a..e600cc53 100644 --- a/src/app/components/message/layout/Channel.tsx +++ b/src/app/components/message/layout/Channel.tsx @@ -98,29 +98,6 @@ export const ChannelLayout = as<'div', ChannelLayoutProps>( ) ); -export type ChannelDayDividerProps = { - label: ReactNode; -}; - -// Section break between days in the channels timeline. Horizontal line -// + centered uppercase label, spans full row including the avatar gutter -// so it reads as a structural separator. -export const ChannelDayDivider = as<'div', ChannelDayDividerProps>( - ({ className, label, ...props }, ref) => ( -
- - {label} - -
- ) -); - export type ChannelEventContentProps = { iconSrc: IconSrc; content: ReactNode; diff --git a/src/app/features/room/RoomTimeline.css.ts b/src/app/features/room/RoomTimeline.css.ts index 43b4945c..c428f470 100644 --- a/src/app/features/room/RoomTimeline.css.ts +++ b/src/app/features/room/RoomTimeline.css.ts @@ -7,7 +7,8 @@ import { VOJO_STICKY_DATE_TOP_PX, } from '../../styles/horseshoe'; -// Bubble (1:1 DM) timeline band — centre the message column in the same band +// Timeline band (every room class — 1:1 bubble, group, channel) — centre the +// message column in the same band // the AI-bot chat uses (ThreadDrawerContentAssistant), so on wide web viewports // the chat is centred instead of spreading edge-to-edge. Inert on mobile (band // > viewport). The composer mirrors this via ComposerBubbleBand; both read the @@ -32,7 +33,8 @@ export const BubbleTimelineBand = style({ }, }); -// Day capsule for the bubble (1:1 DM) timeline («Среда, 4 июня» / «Сегодня») — +// Day capsule for the timeline («Среда, 4 июня» / «Сегодня»), shared by every +// room class (1:1 bubble, group, channel) — // a single dark-blue pill in the message-input tone (Surface.Container, the same // token the composer card paints with), centred, with generous rounding. No // border, no echo. diff --git a/src/app/features/room/RoomTimeline.tsx b/src/app/features/room/RoomTimeline.tsx index b0af31ba..7d4bfda9 100644 --- a/src/app/features/room/RoomTimeline.tsx +++ b/src/app/features/room/RoomTimeline.tsx @@ -48,8 +48,6 @@ import { MSticker, ImageContent, EventContent, - CHANNEL_MESSAGE_SPACING, - ChannelDayDivider, } from '../../components/message'; import { factoryRenderLinkifyWithMention, @@ -1302,7 +1300,8 @@ export function RoomTimeline({ const { t } = useTranslation(); - // Sticky day capsules (bubble layout only). Each day boundary renders a REAL + // Sticky day capsules (every room class — 1:1 bubble, group, channel). Each + // day boundary renders a REAL // capsule that is a CSS `position: sticky` element (see RoomTimeline.css // `[data-sticky-dates='on'] BubbleDayCapsuleRow`). The browser pins it on the // compositor while you scroll through a day, then lets it settle back into its @@ -1319,7 +1318,6 @@ export function RoomTimeline({ // `offsetTop` is the in-flow position (sticky doesn't change it), so the // front detection and the virtual paginator's offsetTop maths stay in agreement. useEffect(() => { - if (messageLayout === 'channel') return undefined; const scrollEl = getScrollElement(); if (!scrollEl) return undefined; @@ -1370,7 +1368,7 @@ export function RoomTimeline({ delete scrollEl.dataset.stickyDates; showAll(); }; - }, [getScrollElement, messageLayout]); + }, [getScrollElement]); // Group `m.call.member` (StateEvent.GroupCallMemberPrefix) events into one // aggregate bubble per CALL SESSION. Each session is delimited by «joined @@ -2635,24 +2633,19 @@ export function RoomTimeline({ return timeDayMonYear(mEvent.getTs()); })(); - const renderDayDivider = () => - messageLayout === 'channel' ? ( - - - - ) : ( - // Bubble (1:1 DM): a centred, single dark-blue date pill. The row is the - // real `position: sticky` element — `data-day-divider` is the hook the - // scroll effect uses to engage stickiness and pick the front pill when - // several pile up. No MessageBase wrapper: the row must be a direct child - // of the timeline column so its sticky containing block is the whole day, - // not a one-row box. -
- - {dayLabel} - -
- ); + const renderDayDivider = () => ( + // Every room class (1:1 bubble, group, channel) draws the same centred, + // single dark-blue date pill. The row is the real `position: sticky` + // element — `data-day-divider` is the hook the scroll effect uses to engage + // stickiness and pick the front pill when several pile up. No MessageBase + // wrapper: the row must be a direct child of the timeline column so its + // sticky containing block is the whole day, not a one-row box. +
+ + {dayLabel} + +
+ ); const dayDividerJSX = dayDivider && eventJSX ? renderDayDivider() : null; @@ -2673,7 +2666,7 @@ export function RoomTimeline({ return ( - {/* Bubble (1:1 DM) day dates are the inline capsules themselves, made + {/* Day dates are the inline capsules themselves (every room class), made sticky via real CSS `position: sticky` (engaged by the effect above) — no separate floating pill. */} {unreadFloatShown && ( @@ -2703,8 +2696,8 @@ export function RoomTimeline({ { const el = composerWrapRef.current; if (!el) { @@ -183,17 +171,11 @@ export function RoomView({ eventId }: { eventId?: string }) { onFocusCapture={() => setComposerHidden(false)} >
{tombstoneEvent ? (