mirror of
https://github.com/fluxerapp/fluxer.git
synced 2026-09-03 05:10:25 +03:00
perf(app): render guild stickers only near the modal viewport (#1964)
This commit is contained in:
@@ -16,10 +16,12 @@ import {getAcceptString, getAssetFormatErrorMessage} from '@app/features/express
|
||||
import {isSvgFile} from '@app/features/expressions/utils/ImageUploadFileUtils';
|
||||
import {CloneAllowedToggle} from '@app/features/guild/components/modals/guild_tabs/CloneAllowedToggle';
|
||||
import styles from '@app/features/guild/components/modals/guild_tabs/GuildStickersTab.module.css';
|
||||
import {resolveEnclosingScrollSurface} from '@app/features/guild/components/modals/guild_tabs/GuildStickersTabScrollSurface';
|
||||
import {UploadDropZone} from '@app/features/guild/components/UploadDropZone';
|
||||
import {UploadSlotInfo} from '@app/features/guild/components/UploadSlotInfo';
|
||||
import Guilds from '@app/features/guild/state/Guilds';
|
||||
import {OKAY_DESCRIPTOR, TRY_AGAIN_DESCRIPTOR} from '@app/features/i18n/utils/CommonMessageDescriptors';
|
||||
import {NearViewportSurfaceContext} from '@app/features/messaging/hooks/useNearViewport';
|
||||
import {openFilePicker} from '@app/features/messaging/utils/FilePickerUtils';
|
||||
import {formatFileSize} from '@app/features/messaging/utils/FileUtils';
|
||||
import Permission from '@app/features/permissions/state/Permission';
|
||||
@@ -42,7 +44,7 @@ import {clsx} from 'clsx';
|
||||
import {matchSorter} from 'match-sorter';
|
||||
import {observer} from 'mobx-react-lite';
|
||||
import type React from 'react';
|
||||
import {useCallback, useEffect, useMemo, useState} from 'react';
|
||||
import {useCallback, useEffect, useMemo, useRef, useState} from 'react';
|
||||
|
||||
const SEARCH_STICKERS_DESCRIPTOR = msg({
|
||||
message: 'Search stickers',
|
||||
@@ -92,6 +94,8 @@ const GuildStickersTab: React.FC<{guildId: string}> = observer(function GuildSti
|
||||
const [stickers, setStickers] = useState<ReadonlyArray<GuildStickerWithUser>>([]);
|
||||
const [fetchStatus, setFetchStatus] = useState<'idle' | 'pending' | 'success' | 'error'>('idle');
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
const gridRef = useRef<HTMLDivElement | null>(null);
|
||||
const resolveGridScrollSurface = useCallback(() => resolveEnclosingScrollSurface(gridRef.current), []);
|
||||
const layoutState = EmojiStickerLayout;
|
||||
const viewMode = layoutState.getStickerViewMode();
|
||||
const guild = Guilds.getGuild(guildId);
|
||||
@@ -309,21 +313,24 @@ const GuildStickersTab: React.FC<{guildId: string}> = observer(function GuildSti
|
||||
/>
|
||||
)}
|
||||
{fetchStatus === 'success' && filteredStickers.length > 0 && (
|
||||
<div
|
||||
className={clsx(styles.stickerGrid, viewMode === 'compact' ? styles.compactGrid : styles.cozyGrid)}
|
||||
data-flx="guild.guild-tabs.guild-stickers-tab.sticker-grid"
|
||||
>
|
||||
{filteredStickers.map((sticker) => (
|
||||
<StickerGridItem
|
||||
key={sticker.id}
|
||||
guildId={guildId}
|
||||
sticker={sticker}
|
||||
canModify={canModifySticker(sticker)}
|
||||
onUpdate={fetchStickers}
|
||||
data-flx="guild.guild-tabs.guild-stickers-tab.sticker-grid-item"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<NearViewportSurfaceContext.Provider value={resolveGridScrollSurface}>
|
||||
<div
|
||||
ref={gridRef}
|
||||
className={clsx(styles.stickerGrid, viewMode === 'compact' ? styles.compactGrid : styles.cozyGrid)}
|
||||
data-flx="guild.guild-tabs.guild-stickers-tab.sticker-grid"
|
||||
>
|
||||
{filteredStickers.map((sticker) => (
|
||||
<StickerGridItem
|
||||
key={sticker.id}
|
||||
guildId={guildId}
|
||||
sticker={sticker}
|
||||
canModify={canModifySticker(sticker)}
|
||||
onUpdate={fetchStickers}
|
||||
data-flx="guild.guild-tabs.guild-stickers-tab.sticker-grid-item"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</NearViewportSurfaceContext.Provider>
|
||||
)}
|
||||
{fetchStatus === 'error' && (
|
||||
<StatusSlate
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
const SCROLLABLE_OVERFLOW_VALUES = new Set(['auto', 'scroll', 'overlay']);
|
||||
|
||||
export function resolveEnclosingScrollSurface(node: Element | null): Element | null {
|
||||
let candidate = node?.parentElement ?? null;
|
||||
while (candidate) {
|
||||
const computedStyle = window.getComputedStyle(candidate);
|
||||
if (
|
||||
SCROLLABLE_OVERFLOW_VALUES.has(computedStyle.overflowY) ||
|
||||
SCROLLABLE_OVERFLOW_VALUES.has(computedStyle.overflow)
|
||||
) {
|
||||
return candidate;
|
||||
}
|
||||
candidate = candidate.parentElement;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
Reference in New Issue
Block a user