chore: prettier format all files, brotli, Sentry release tagging, CI gates

Prettier: auto-formatted 103 files to fix baseline. Prettier check in CI
  is now a hard gate (removed continue-on-error).

Brotli: installed libnginx-mod-http-brotli-filter/static. Enabled in nginx
  with brotli_static on for pre-compressed assets and comp_level 6.

Sentry releases: deploy script now exports VITE_APP_VERSION=<git-short-sha>
  before building so each Sentry release maps to an exact commit.
  CI also passes github.sha as VITE_APP_VERSION.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lotus Bot
2026-05-21 20:49:33 -04:00
parent 408fc1b846
commit 42b9cc2b64
105 changed files with 2749 additions and 1850 deletions
+6 -1
View File
@@ -41,7 +41,12 @@ export function CallChatView() {
}
>
{(triggerRef) => (
<IconButton ref={triggerRef} variant="Surface" onClick={handleClose} aria-label="Close call chat">
<IconButton
ref={triggerRef}
variant="Surface"
onClick={handleClose}
aria-label="Close call chat"
>
<Icon src={Icons.Cross} />
</IconButton>
)}
+68 -31
View File
@@ -30,7 +30,9 @@ import {
} from 'folds';
import { useMatrixClient } from '../../hooks/useMatrixClient';
const GifPicker = React.lazy(() => import('../../components/GifPicker').then((m) => ({ default: m.GifPicker })));
const GifPicker = React.lazy(() =>
import('../../components/GifPicker').then((m) => ({ default: m.GifPicker }))
);
import { useClientConfig } from '../../hooks/useClientConfig';
import {
CustomEditor,
@@ -57,7 +59,9 @@ import {
getMentions,
} from '../../components/editor';
import { EmojiBoardTab } from '../../components/emoji-board/types';
const EmojiBoard = React.lazy(() => import('../../components/emoji-board').then((m) => ({ default: m.EmojiBoard })));
const EmojiBoard = React.lazy(() =>
import('../../components/emoji-board').then((m) => ({ default: m.EmojiBoard }))
);
import { UseStateProvider } from '../../components/UseStateProvider';
import {
TUploadContent,
@@ -143,7 +147,7 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
const powerLevels = usePowerLevelsContext();
const creators = useRoomCreators(room);
const alive = useAlive();
const alive = useAlive();
const [msgDraft, setMsgDraft] = useAtom(roomIdToMsgDraftAtomFamily(roomId));
const [replyDraft, setReplyDraft] = useAtom(roomIdToReplyDraftAtomFamily(roomId));
const replyUserID = replyDraft?.userId;
@@ -467,8 +471,15 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
async (gifUrl: string, w: number, h: number) => {
try {
// Only fetch from trusted Giphy CDN domains
const allowed = ['media.giphy.com', 'i.giphy.com', 'media0.giphy.com',
'media1.giphy.com', 'media2.giphy.com', 'media3.giphy.com', 'media4.giphy.com'];
const allowed = [
'media.giphy.com',
'i.giphy.com',
'media0.giphy.com',
'media1.giphy.com',
'media2.giphy.com',
'media3.giphy.com',
'media4.giphy.com',
];
const { hostname } = new URL(gifUrl);
if (!allowed.includes(hostname)) return;
@@ -695,24 +706,26 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
: emojiBtnRef.current?.getBoundingClientRect() ?? undefined
}
content={
<React.Suspense fallback={null}><EmojiBoard
tab={emojiBoardTab}
onTabChange={setEmojiBoardTab}
imagePackRooms={imagePackRooms}
returnFocusOnDeactivate={false}
onEmojiSelect={handleEmoticonSelect}
onCustomEmojiSelect={handleEmoticonSelect}
onStickerSelect={handleStickerSelect}
requestClose={() => {
setEmojiBoardTab((t) => {
if (t) {
if (!mobileOrTablet()) ReactEditor.focus(editor);
return undefined;
}
return t;
});
}}
/></React.Suspense>
<React.Suspense fallback={null}>
<EmojiBoard
tab={emojiBoardTab}
onTabChange={setEmojiBoardTab}
imagePackRooms={imagePackRooms}
returnFocusOnDeactivate={false}
onEmojiSelect={handleEmoticonSelect}
onCustomEmojiSelect={handleEmoticonSelect}
onStickerSelect={handleStickerSelect}
requestClose={() => {
setEmojiBoardTab((t) => {
if (t) {
if (!mobileOrTablet()) ReactEditor.focus(editor);
return undefined;
}
return t;
});
}}
/>
</React.Suspense>
}
>
{!hideStickerBtn && (
@@ -765,11 +778,13 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
: undefined
}
content={
<React.Suspense fallback={null}><GifPicker
apiKey={gifApiKey}
onSelect={handleGifSelect}
requestClose={() => setGifOpen(false)}
/></React.Suspense>
<React.Suspense fallback={null}>
<GifPicker
apiKey={gifApiKey}
onSelect={handleGifSelect}
requestClose={() => setGifOpen(false)}
/>
</React.Suspense>
}
>
<IconButton
@@ -798,7 +813,15 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
</UseStateProvider>
)}
{gifError && (
<Text size="T100" style={{ color: 'var(--tc-danger-normal)', padding: '2px 6px', alignSelf: 'center', whiteSpace: 'nowrap' }}>
<Text
size="T100"
style={{
color: 'var(--tc-danger-normal)',
padding: '2px 6px',
alignSelf: 'center',
whiteSpace: 'nowrap',
}}
>
{gifError}
</Text>
)}
@@ -811,14 +834,28 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
title="Share location"
>
{locating ? (
<Text size="T200" style={{ fontWeight: 800, fontSize: '10px', letterSpacing: '0.04em', lineHeight: 1 }}>
<Text
size="T200"
style={{
fontWeight: 800,
fontSize: '10px',
letterSpacing: '0.04em',
lineHeight: 1,
}}
>
...
</Text>
) : (
<Icon src={Icons.Pin} size="100" />
)}
</IconButton>
<IconButton onClick={submit} variant="SurfaceVariant" size="300" radii="300" aria-label="Send message">
<IconButton
onClick={submit}
variant="SurfaceVariant"
size="300"
radii="300"
aria-label="Send message"
>
<Icon src={Icons.Send} />
</IconButton>
</>
+277 -147
View File
@@ -637,7 +637,7 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
// and either there are no unread messages or the latest message is from the current user.
// If either condition is met, trigger the markAsRead function to send a read receipt.
const _roomId = mEvt.getRoomId();
if (_roomId) requestAnimationFrame(() => markAsRead(mx, _roomId, hideActivity));
if (_roomId) requestAnimationFrame(() => markAsRead(mx, _roomId, hideActivity));
}
if (!document.hasFocus() && !unreadInfo) {
@@ -673,7 +673,8 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
) => {
const evtTimeline = getEventTimeline(room, evtId);
const absoluteIndex =
evtTimeline && getEventIdAbsoluteIndex(timelineRef.current.linkedTimelines, evtTimeline, evtId);
evtTimeline &&
getEventIdAbsoluteIndex(timelineRef.current.linkedTimelines, evtTimeline, evtId);
if (typeof absoluteIndex === 'number') {
const scrolled = scrollToItem(absoluteIndex, {
@@ -1242,7 +1243,13 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
mEvent.getType() === 'm.poll.start' ||
mEvent.getType() === 'org.matrix.msc3381.poll.start'
)
return <PollContent content={mEvent.getContent()} roomId={room.roomId} eventId={mEvent.getId() ?? undefined} />;
return (
<PollContent
content={mEvent.getContent()}
roomId={room.roomId}
eventId={mEvent.getId() ?? undefined}
/>
);
if (mEvent.getType() === MessageEvent.RoomMessageEncrypted)
return (
<Text>
@@ -1371,7 +1378,11 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
{mEvent.isRedacted() ? (
<RedactedContent reason={mEvent.getUnsigned().redacted_because?.content.reason} />
) : (
<PollContent content={mEvent.getContent()} roomId={room.roomId} eventId={mEvent.getId() ?? undefined} />
<PollContent
content={mEvent.getContent()}
roomId={room.roomId}
eventId={mEvent.getId() ?? undefined}
/>
)}
</Message>
);
@@ -1424,7 +1435,11 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
{mEvent.isRedacted() ? (
<RedactedContent reason={mEvent.getUnsigned().redacted_because?.content.reason} />
) : (
<PollContent content={mEvent.getContent()} roomId={room.roomId} eventId={mEvent.getId() ?? undefined} />
<PollContent
content={mEvent.getContent()}
roomId={room.roomId}
eventId={mEvent.getId() ?? undefined}
/>
)}
</Message>
);
@@ -1608,12 +1623,38 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
const senderId = mEvent.getSender() ?? '';
const senderName = getMemberDisplayName(room, senderId) || getMxIdLocalPart(senderId);
const timeJSX = (
<Time ts={mEvent.getTs()} compact={messageLayout === MessageLayout.Compact} hour24Clock={hour24Clock} dateFormatString={dateFormatString} />
<Time
ts={mEvent.getTs()}
compact={messageLayout === MessageLayout.Compact}
hour24Clock={hour24Clock}
dateFormatString={dateFormatString}
/>
);
return (
<Event key={mEvent.getId()} data-message-item={item} data-message-id={mEventId} room={room} mEvent={mEvent} highlight={highlighted} messageSpacing={messageSpacing} canDelete={canRedact || mEvent.getSender() === mx.getUserId()} hideReadReceipts={hideActivity} showDeveloperTools={showDeveloperTools}>
<EventContent messageLayout={messageLayout} time={timeJSX} iconSrc={Icons.Lock}
content={<Box grow="Yes" direction="Column"><Text size="T300" priority="300"><b>{senderName}</b>{' enabled end-to-end encryption'}</Text></Box>}
<Event
key={mEvent.getId()}
data-message-item={item}
data-message-id={mEventId}
room={room}
mEvent={mEvent}
highlight={highlighted}
messageSpacing={messageSpacing}
canDelete={canRedact || mEvent.getSender() === mx.getUserId()}
hideReadReceipts={hideActivity}
showDeveloperTools={showDeveloperTools}
>
<EventContent
messageLayout={messageLayout}
time={timeJSX}
iconSrc={Icons.Lock}
content={
<Box grow="Yes" direction="Column">
<Text size="T300" priority="300">
<b>{senderName}</b>
{' enabled end-to-end encryption'}
</Text>
</Box>
}
/>
</Event>
);
@@ -1623,14 +1664,45 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
const senderId = mEvent.getSender() ?? '';
const senderName = getMemberDisplayName(room, senderId) || getMxIdLocalPart(senderId);
const joinRule = mEvent.getContent<{ join_rule?: string }>().join_rule ?? 'unknown';
const ruleLabel: Record<string, string> = { public: 'public', invite: 'invite-only', knock: 'knock', restricted: 'restricted' };
const ruleLabel: Record<string, string> = {
public: 'public',
invite: 'invite-only',
knock: 'knock',
restricted: 'restricted',
};
const timeJSX = (
<Time ts={mEvent.getTs()} compact={messageLayout === MessageLayout.Compact} hour24Clock={hour24Clock} dateFormatString={dateFormatString} />
<Time
ts={mEvent.getTs()}
compact={messageLayout === MessageLayout.Compact}
hour24Clock={hour24Clock}
dateFormatString={dateFormatString}
/>
);
return (
<Event key={mEvent.getId()} data-message-item={item} data-message-id={mEventId} room={room} mEvent={mEvent} highlight={highlighted} messageSpacing={messageSpacing} canDelete={canRedact || mEvent.getSender() === mx.getUserId()} hideReadReceipts={hideActivity} showDeveloperTools={showDeveloperTools}>
<EventContent messageLayout={messageLayout} time={timeJSX} iconSrc={Icons.Settings}
content={<Box grow="Yes" direction="Column"><Text size="T300" priority="300"><b>{senderName}</b>{` set room join rule to ${ruleLabel[joinRule] ?? joinRule}`}</Text></Box>}
<Event
key={mEvent.getId()}
data-message-item={item}
data-message-id={mEventId}
room={room}
mEvent={mEvent}
highlight={highlighted}
messageSpacing={messageSpacing}
canDelete={canRedact || mEvent.getSender() === mx.getUserId()}
hideReadReceipts={hideActivity}
showDeveloperTools={showDeveloperTools}
>
<EventContent
messageLayout={messageLayout}
time={timeJSX}
iconSrc={Icons.Settings}
content={
<Box grow="Yes" direction="Column">
<Text size="T300" priority="300">
<b>{senderName}</b>
{` set room join rule to ${ruleLabel[joinRule] ?? joinRule}`}
</Text>
</Box>
}
/>
</Event>
);
@@ -1641,12 +1713,38 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
const senderName = getMemberDisplayName(room, senderId) || getMxIdLocalPart(senderId);
const access = mEvent.getContent<{ guest_access?: string }>().guest_access ?? 'unknown';
const timeJSX = (
<Time ts={mEvent.getTs()} compact={messageLayout === MessageLayout.Compact} hour24Clock={hour24Clock} dateFormatString={dateFormatString} />
<Time
ts={mEvent.getTs()}
compact={messageLayout === MessageLayout.Compact}
hour24Clock={hour24Clock}
dateFormatString={dateFormatString}
/>
);
return (
<Event key={mEvent.getId()} data-message-item={item} data-message-id={mEventId} room={room} mEvent={mEvent} highlight={highlighted} messageSpacing={messageSpacing} canDelete={canRedact || mEvent.getSender() === mx.getUserId()} hideReadReceipts={hideActivity} showDeveloperTools={showDeveloperTools}>
<EventContent messageLayout={messageLayout} time={timeJSX} iconSrc={Icons.Settings}
content={<Box grow="Yes" direction="Column"><Text size="T300" priority="300"><b>{senderName}</b>{access === 'can_join' ? ' allowed guest access' : ' disabled guest access'}</Text></Box>}
<Event
key={mEvent.getId()}
data-message-item={item}
data-message-id={mEventId}
room={room}
mEvent={mEvent}
highlight={highlighted}
messageSpacing={messageSpacing}
canDelete={canRedact || mEvent.getSender() === mx.getUserId()}
hideReadReceipts={hideActivity}
showDeveloperTools={showDeveloperTools}
>
<EventContent
messageLayout={messageLayout}
time={timeJSX}
iconSrc={Icons.Settings}
content={
<Box grow="Yes" direction="Column">
<Text size="T300" priority="300">
<b>{senderName}</b>
{access === 'can_join' ? ' allowed guest access' : ' disabled guest access'}
</Text>
</Box>
}
/>
</Event>
);
@@ -1657,12 +1755,38 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
const senderName = getMemberDisplayName(room, senderId) || getMxIdLocalPart(senderId);
const alias = mEvent.getContent<{ alias?: string }>().alias;
const timeJSX = (
<Time ts={mEvent.getTs()} compact={messageLayout === MessageLayout.Compact} hour24Clock={hour24Clock} dateFormatString={dateFormatString} />
<Time
ts={mEvent.getTs()}
compact={messageLayout === MessageLayout.Compact}
hour24Clock={hour24Clock}
dateFormatString={dateFormatString}
/>
);
return (
<Event key={mEvent.getId()} data-message-item={item} data-message-id={mEventId} room={room} mEvent={mEvent} highlight={highlighted} messageSpacing={messageSpacing} canDelete={canRedact || mEvent.getSender() === mx.getUserId()} hideReadReceipts={hideActivity} showDeveloperTools={showDeveloperTools}>
<EventContent messageLayout={messageLayout} time={timeJSX} iconSrc={Icons.Hash}
content={<Box grow="Yes" direction="Column"><Text size="T300" priority="300"><b>{senderName}</b>{alias ? ` set room address to ${alias}` : ' removed room address'}</Text></Box>}
<Event
key={mEvent.getId()}
data-message-item={item}
data-message-id={mEventId}
room={room}
mEvent={mEvent}
highlight={highlighted}
messageSpacing={messageSpacing}
canDelete={canRedact || mEvent.getSender() === mx.getUserId()}
hideReadReceipts={hideActivity}
showDeveloperTools={showDeveloperTools}
>
<EventContent
messageLayout={messageLayout}
time={timeJSX}
iconSrc={Icons.Hash}
content={
<Box grow="Yes" direction="Column">
<Text size="T300" priority="300">
<b>{senderName}</b>
{alias ? ` set room address to ${alias}` : ' removed room address'}
</Text>
</Box>
}
/>
</Event>
);
@@ -1831,9 +1955,15 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
while (lo <= hi) {
const mid = (lo + hi) >>> 1;
const [base, len] = timelineSegments[mid];
if (item < base) { hi = mid - 1; }
else if (item >= base + len) { lo = mid + 1; }
else { eventTimeline = timelineSegments[mid][2]; baseIndex = base; break; }
if (item < base) {
hi = mid - 1;
} else if (item >= base + len) {
lo = mid + 1;
} else {
eventTimeline = timelineSegments[mid][2];
baseIndex = base;
break;
}
}
}
if (!eventTimeline) return null;
@@ -1935,131 +2065,131 @@ export function RoomTimeline({ room, eventId, roomInputRef, editor }: RoomTimeli
return (
<ReadPositionsContext.Provider value={readPositions}>
<Box grow="Yes" style={{ position: 'relative' }}>
{unreadInfo?.readUptoEventId && !unreadInfo?.inLiveTimeline && (
<TimelineFloat position="Top">
<Chip
variant="Primary"
radii="Pill"
outlined
before={<Icon size="50" src={Icons.MessageUnread} />}
onClick={handleJumpToUnread}
>
<Text size="L400">Jump to Unread</Text>
</Chip>
<Chip
variant="SurfaceVariant"
radii="Pill"
outlined
before={<Icon size="50" src={Icons.CheckTwice} />}
onClick={handleMarkAsRead}
>
<Text size="L400">Mark as Read</Text>
</Chip>
</TimelineFloat>
)}
<Scroll ref={scrollRef} visibility="Hover">
<Box
direction="Column"
justifyContent="End"
style={{ minHeight: '100%', padding: `${config.space.S600} 0` }}
>
{!canPaginateBack && rangeAtStart && getItems().length > 0 && (
<div
style={{
padding: `${config.space.S700} ${config.space.S400} ${config.space.S600} ${
messageLayout === MessageLayout.Compact ? config.space.S400 : toRem(64)
}`,
}}
<Box grow="Yes" style={{ position: 'relative' }}>
{unreadInfo?.readUptoEventId && !unreadInfo?.inLiveTimeline && (
<TimelineFloat position="Top">
<Chip
variant="Primary"
radii="Pill"
outlined
before={<Icon size="50" src={Icons.MessageUnread} />}
onClick={handleJumpToUnread}
>
<RoomIntro room={room} />
</div>
)}
{(canPaginateBack || !rangeAtStart) &&
(messageLayout === MessageLayout.Compact ? (
<>
<MessageBase>
<CompactPlaceholder key={getItems().length} />
</MessageBase>
<MessageBase>
<CompactPlaceholder key={getItems().length} />
</MessageBase>
<MessageBase>
<CompactPlaceholder key={getItems().length} />
</MessageBase>
<MessageBase>
<CompactPlaceholder key={getItems().length} />
</MessageBase>
<MessageBase ref={observeBackAnchor}>
<CompactPlaceholder key={getItems().length} />
</MessageBase>
</>
) : (
<>
<MessageBase>
<DefaultPlaceholder key={getItems().length} />
</MessageBase>
<MessageBase>
<DefaultPlaceholder key={getItems().length} />
</MessageBase>
<MessageBase ref={observeBackAnchor}>
<DefaultPlaceholder key={getItems().length} />
</MessageBase>
</>
))}
<Text size="L400">Jump to Unread</Text>
</Chip>
{getItems().map(eventRenderer)}
{(!liveTimelineLinked || !rangeAtEnd) &&
(messageLayout === MessageLayout.Compact ? (
<>
<MessageBase ref={observeFrontAnchor}>
<CompactPlaceholder key={getItems().length} />
</MessageBase>
<MessageBase>
<CompactPlaceholder key={getItems().length} />
</MessageBase>
<MessageBase>
<CompactPlaceholder key={getItems().length} />
</MessageBase>
<MessageBase>
<CompactPlaceholder key={getItems().length} />
</MessageBase>
<MessageBase>
<CompactPlaceholder key={getItems().length} />
</MessageBase>
</>
) : (
<>
<MessageBase ref={observeFrontAnchor}>
<DefaultPlaceholder key={getItems().length} />
</MessageBase>
<MessageBase>
<DefaultPlaceholder key={getItems().length} />
</MessageBase>
<MessageBase>
<DefaultPlaceholder key={getItems().length} />
</MessageBase>
</>
))}
<span ref={atBottomAnchorRef} />
</Box>
</Scroll>
{!atBottom && (
<TimelineFloat position="Bottom">
<Chip
variant="SurfaceVariant"
radii="Pill"
outlined
before={<Icon size="50" src={Icons.ArrowBottom} />}
onClick={handleJumpToLatest}
<Chip
variant="SurfaceVariant"
radii="Pill"
outlined
before={<Icon size="50" src={Icons.CheckTwice} />}
onClick={handleMarkAsRead}
>
<Text size="L400">Mark as Read</Text>
</Chip>
</TimelineFloat>
)}
<Scroll ref={scrollRef} visibility="Hover">
<Box
direction="Column"
justifyContent="End"
style={{ minHeight: '100%', padding: `${config.space.S600} 0` }}
>
<Text size="L400">Jump to Latest</Text>
</Chip>
</TimelineFloat>
)}
</Box>
{!canPaginateBack && rangeAtStart && getItems().length > 0 && (
<div
style={{
padding: `${config.space.S700} ${config.space.S400} ${config.space.S600} ${
messageLayout === MessageLayout.Compact ? config.space.S400 : toRem(64)
}`,
}}
>
<RoomIntro room={room} />
</div>
)}
{(canPaginateBack || !rangeAtStart) &&
(messageLayout === MessageLayout.Compact ? (
<>
<MessageBase>
<CompactPlaceholder key={getItems().length} />
</MessageBase>
<MessageBase>
<CompactPlaceholder key={getItems().length} />
</MessageBase>
<MessageBase>
<CompactPlaceholder key={getItems().length} />
</MessageBase>
<MessageBase>
<CompactPlaceholder key={getItems().length} />
</MessageBase>
<MessageBase ref={observeBackAnchor}>
<CompactPlaceholder key={getItems().length} />
</MessageBase>
</>
) : (
<>
<MessageBase>
<DefaultPlaceholder key={getItems().length} />
</MessageBase>
<MessageBase>
<DefaultPlaceholder key={getItems().length} />
</MessageBase>
<MessageBase ref={observeBackAnchor}>
<DefaultPlaceholder key={getItems().length} />
</MessageBase>
</>
))}
{getItems().map(eventRenderer)}
{(!liveTimelineLinked || !rangeAtEnd) &&
(messageLayout === MessageLayout.Compact ? (
<>
<MessageBase ref={observeFrontAnchor}>
<CompactPlaceholder key={getItems().length} />
</MessageBase>
<MessageBase>
<CompactPlaceholder key={getItems().length} />
</MessageBase>
<MessageBase>
<CompactPlaceholder key={getItems().length} />
</MessageBase>
<MessageBase>
<CompactPlaceholder key={getItems().length} />
</MessageBase>
<MessageBase>
<CompactPlaceholder key={getItems().length} />
</MessageBase>
</>
) : (
<>
<MessageBase ref={observeFrontAnchor}>
<DefaultPlaceholder key={getItems().length} />
</MessageBase>
<MessageBase>
<DefaultPlaceholder key={getItems().length} />
</MessageBase>
<MessageBase>
<DefaultPlaceholder key={getItems().length} />
</MessageBase>
</>
))}
<span ref={atBottomAnchorRef} />
</Box>
</Scroll>
{!atBottom && (
<TimelineFloat position="Bottom">
<Chip
variant="SurfaceVariant"
radii="Pill"
outlined
before={<Icon size="50" src={Icons.ArrowBottom} />}
onClick={handleJumpToLatest}
>
<Text size="L400">Jump to Latest</Text>
</Chip>
</TimelineFloat>
)}
</Box>
</ReadPositionsContext.Provider>
);
}
+3 -4
View File
@@ -56,8 +56,6 @@ const shouldFocusMessageField = (evt: KeyboardEvent): boolean => {
return true;
};
export function RoomView({ eventId }: { eventId?: string }) {
const roomInputRef = useRef<HTMLDivElement>(null);
const roomViewRef = useRef<HTMLDivElement>(null);
@@ -98,8 +96,9 @@ export function RoomView({ eventId }: { eventId?: string }) {
)
);
const chatBgStyle = useMemo(
() => getChatBg(lotusTerminal && chatBackground === 'none' ? 'tactical' : chatBackground, isDark),
const chatBgStyle = useMemo(
() =>
getChatBg(lotusTerminal && chatBackground === 'none' ? 'tactical' : chatBackground, isDark),
[chatBackground, lotusTerminal, isDark]
);
+19 -7
View File
@@ -533,7 +533,12 @@ export function RoomViewHeader({ callView }: { callView?: boolean }) {
}
>
{(triggerRef) => (
<IconButton fill="None" ref={triggerRef} onClick={handleSearchClick} aria-label="Search">
<IconButton
fill="None"
ref={triggerRef}
onClick={handleSearchClick}
aria-label="Search"
>
<Icon size="400" src={Icons.Search} />
</IconButton>
)}
@@ -596,11 +601,13 @@ export function RoomViewHeader({ callView }: { callView?: boolean }) {
</FocusTrap>
}
/>
{!room.isCallRoom() && livekitSupported && rtcSupported && hasCallPermission &&
(direct || (room.getJoinRule() === 'invite' &&
getStateEvents(room, StateEvent.SpaceParent).length === 0)) && (
<CallButton />
)}
{!room.isCallRoom() &&
livekitSupported &&
rtcSupported &&
hasCallPermission &&
(direct ||
(room.getJoinRule() === 'invite' &&
getStateEvents(room, StateEvent.SpaceParent).length === 0)) && <CallButton />}
{screenSize === ScreenSize.Desktop && (
<TooltipProvider
position="Bottom"
@@ -616,7 +623,12 @@ export function RoomViewHeader({ callView }: { callView?: boolean }) {
}
>
{(triggerRef) => (
<IconButton fill="None" ref={triggerRef} onClick={handleMemberToggle} aria-label="Toggle member list">
<IconButton
fill="None"
ref={triggerRef}
onClick={handleMemberToggle}
aria-label="Toggle member list"
>
<Icon size="400" src={Icons.User} />
</IconButton>
)}
+7 -1
View File
@@ -117,7 +117,13 @@ export const RoomViewTyping = as<'div', RoomViewTypingProps>(
</>
)}
</Text>
<IconButton title="Drop Typing Status" aria-label="Drop typing status" size="300" radii="Pill" onClick={handleDropAll}>
<IconButton
title="Drop Typing Status"
aria-label="Drop typing status"
size="300"
radii="Pill"
onClick={handleDropAll}
>
<Icon size="50" src={Icons.Cross} />
</IconButton>
</Box>
@@ -57,7 +57,12 @@ export function ForwardMessageDialog({ mEvent, onClose }: Props) {
>
<Modal
size="400"
style={{ maxHeight: '440px', borderRadius: config.radii.R500, display: 'flex', flexDirection: 'column' }}
style={{
maxHeight: '440px',
borderRadius: config.radii.R500,
display: 'flex',
flexDirection: 'column',
}}
>
<Box
direction="Column"
@@ -89,11 +94,7 @@ export function ForwardMessageDialog({ mEvent, onClose }: Props) {
) : (
<Box grow="Yes" style={{ minHeight: 0 }}>
<Scroll size="300" hideTrack visibility="Hover">
<Box
direction="Column"
gap="100"
style={{ padding: config.space.S200 }}
>
<Box direction="Column" gap="100" style={{ padding: config.space.S200 }}>
{filtered.slice(0, 60).map((room) => (
<MenuItem
key={room.roomId}
File diff suppressed because it is too large Load Diff