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 ? (