fix(app): fade messages behind the composer status row (#3020)

This commit is contained in:
Hampus
2026-09-28 18:47:42 +02:00
committed by GitHub
parent c9ae5b6ee8
commit 997d98c65c
6 changed files with 50 additions and 35 deletions
@@ -557,10 +557,6 @@ const SKELETON_SURFACE_INVARIANTS: ReadonlyArray<SkeletonSurfaceInvariant> = [
file: 'src/features/channel/components/MemberListSkeleton.tsx',
counts: {'style={MEMBER_LIST_METRICS_STYLE}': 2},
},
{
file: 'src/features/channel/components/textarea/InputWrapper.module.css',
requires: ['.composerRoot:has(.statusTypingSlot, .statusSlowmodeSlot)::before'],
},
{
file: 'src/features/app/components/layout/GuildsLayout.module.css',
requires: [
@@ -14,6 +14,8 @@
}
.scrollerContainer {
--scroller-track-block-end-inset: var(--composer-status-safe-area, 0px);
--messages-bottom-fade-fill: var(--composer-surface-color, var(--background-secondary-lighter));
position: absolute;
inset: 0;
display: flex;
@@ -24,6 +26,36 @@
width: 100%;
}
.bottomFade {
position: absolute;
inset-block-end: 0;
inset-inline: 0 1rem;
z-index: 1;
height: 1rem;
background: linear-gradient(to bottom, transparent, var(--messages-bottom-fade-fill));
pointer-events: none;
}
.bottomFadeStatusAtBottom {
height: var(--composer-status-safe-area);
background: linear-gradient(
to bottom,
transparent,
var(--messages-bottom-fade-fill) var(--composer-status-safe-gap),
var(--messages-bottom-fade-fill) 100%
);
}
.bottomFadeStatusScrolled {
height: calc(var(--composer-status-safe-area) + 4rem);
background: linear-gradient(
to bottom,
transparent,
var(--messages-bottom-fade-fill) calc(4rem + var(--composer-status-safe-gap)),
var(--messages-bottom-fade-fill) 100%
);
}
.scrollerContent {
display: flex;
flex-direction: column;
@@ -14,6 +14,7 @@ import styles from '@app/features/channel/components/ChannelMessages.module.css'
import {ChannelWelcomeSection} from '@app/features/channel/components/ChannelWelcomeSection';
import {CollapsedMessageVisibilityProvider} from '@app/features/channel/components/CollapsedMessageVisibilityContext';
import {NewMessagesBar} from '@app/features/channel/components/NewMessagesBar';
import {usePresentableTypingUsers} from '@app/features/channel/components/TypingUsers';
import {UploadManager} from '@app/features/channel/components/UploadManager';
import type {Channel} from '@app/features/channel/models/Channel';
import GatewayConnection from '@app/features/gateway/transport/GatewayConnection';
@@ -637,6 +638,7 @@ export const Messages = observer(function Messages({
? i18n._(MESSAGE_LIST_FOR_DESCRIPTOR, {channelName: channel.name})
: i18n._(MESSAGE_LIST_DESCRIPTOR);
const messageListLiveMode = Accessibility.screenReaderAnnounceNewMessages && state.isAtBottom ? 'polite' : 'off';
const composerStatusVisible = usePresentableTypingUsers(channel).length > 0 || channel.rateLimitPerUser > 0;
const topFillerVisible = selectChannelMessagesFillerVisible({
reducedMotion: Accessibility.useReducedMotion,
scrollManagerInitialized: scrollManager.lifecycleIsInitialized(),
@@ -719,6 +721,15 @@ export const Messages = observer(function Messages({
</div>
</div>
</Scroller>
<div
className={clsx(
styles.bottomFade,
composerStatusVisible &&
(state.isAtBottom ? styles.bottomFadeStatusAtBottom : styles.bottomFadeStatusScrolled),
)}
aria-hidden="true"
data-flx="channel.messages.bottom-fade"
/>
</div>
{bottomBar}
</div>
@@ -3,7 +3,7 @@
.container {
display: flex;
align-items: center;
gap: 0.1875rem;
gap: 0.25rem;
height: var(--slowmode-indicator-height, 1.125rem);
max-width: 100%;
min-width: 0;
@@ -22,9 +22,9 @@
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-weight: 600;
font-weight: 500;
font-size: 0.75rem;
line-height: 1;
line-height: 1rem;
font-variant-numeric: tabular-nums;
}
@@ -115,15 +115,15 @@ export const SlowmodeIndicator = observer(({slowmodeRemaining, slowmodeDuration,
className={clsx(styles.container, onCooldown && styles.cooldown)}
data-flx="channel.slowmode-indicator.container"
>
<span className={styles.label} data-flx="channel.slowmode-indicator.label">
{statusLabel}
</span>
<ClockIcon
size={remFromPx(12)}
weight="fill"
className={styles.icon}
data-flx="channel.slowmode-indicator.clock-icon"
/>
<span className={styles.label} data-flx="channel.slowmode-indicator.label">
{statusLabel}
</span>
</div>
</Tooltip>
);
@@ -48,28 +48,6 @@
--composer-surface-fill: var(--composer-surface-color, var(--background-secondary-lighter));
}
.composerRoot:has(.statusTypingSlot, .statusSlowmodeSlot)::before {
content: '';
position: absolute;
bottom: 100%;
inset-inline: calc(-1 * var(--composer-box-inset-inline, 0px));
height: var(--composer-status-safe-area);
background:
radial-gradient(farthest-side at 0% 100%, var(--composer-surface-fill) 55%, transparent 100%) left bottom /
min(28rem, 70%) 160% no-repeat,
radial-gradient(farthest-side at 100% 100%, var(--composer-surface-fill) 55%, transparent 100%) right bottom /
min(18rem, 50%) 160% no-repeat,
linear-gradient(
to bottom,
transparent 0%,
color-mix(in srgb, var(--composer-surface-fill) 64%, transparent) 20%,
color-mix(in srgb, var(--composer-surface-fill) 92%, transparent) 40%,
var(--composer-surface-fill) 60%,
var(--composer-surface-fill) 100%
);
pointer-events: none;
}
.statusRail {
--typing-pill-height: var(--composer-status-line-height, 1.125rem);
--slowmode-indicator-height: var(--composer-status-line-height, 1.125rem);
@@ -85,9 +63,6 @@
max-width: 100%;
height: var(--composer-status-line-height, 1.125rem);
box-sizing: border-box;
text-shadow:
0 0 0.1875rem var(--composer-surface-fill),
0 0 0.5rem var(--composer-surface-fill);
pointer-events: none;
}
@@ -117,6 +92,7 @@
min-width: 0;
max-width: min(14rem, 35vw);
justify-self: end;
padding-inline-end: max(0px, calc(1rem - var(--composer-box-padding-inline, 0px)));
pointer-events: auto;
}