mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-18 05:25:40 +09:00
fix(app): keep sticker sizes fixed while resizing the expression picker
This commit is contained in:
1 parent
58732f7770
commit
154e223284
4 files changed
+55
-17
No files matched your search
@@ -14,10 +14,11 @@ import {useVirtualRows} from '@app/features/channel/components/sticker_picker/ho
|
||||
import {StickerPickerCategoryList} from '@app/features/channel/components/sticker_picker/StickerPickerCategoryList';
|
||||
import {
|
||||
buildStickerRowOffsets,
|
||||
getStickerRowHeight,
|
||||
getFixedStickerRowHeight,
|
||||
getStickerGridColumns,
|
||||
getStickerRowWindow,
|
||||
STICKER_GRID_TRACK_WIDTH,
|
||||
STICKER_SECTION_GAP,
|
||||
STICKERS_PER_ROW,
|
||||
type StickerRowKind,
|
||||
} from '@app/features/channel/components/sticker_picker/StickerPickerConstants';
|
||||
import {StickerPickerInspector} from '@app/features/channel/components/sticker_picker/StickerPickerInspector';
|
||||
@@ -74,12 +75,12 @@ export const StickersPicker = observer(
|
||||
const [selectedColumn, setSelectedColumn] = useState(-1);
|
||||
const [shouldScrollOnSelection, setShouldScrollOnSelection] = useState(false);
|
||||
const scrollerRef = useRef<ScrollerHandle>(null);
|
||||
const {scrollTop, handleScroll, handleResize} = useScrollerViewport(scrollerRef);
|
||||
const {viewportSize, scrollTop, handleScroll, handleResize} = useScrollerViewport(scrollerRef);
|
||||
const searchInputRef = useRef<HTMLInputElement>(null);
|
||||
const stickerRefs = useRef<Map<string, HTMLButtonElement>>(new Map());
|
||||
const channel = channelId ? (Channels.getChannel(channelId) ?? null) : null;
|
||||
const rowListRef = useRef<HTMLDivElement>(null);
|
||||
const [listMetrics, setListMetrics] = useState({origin: 0, viewportHeight: 0, gridWidth: 0});
|
||||
const [listMetrics, setListMetrics] = useState({origin: 0, viewportHeight: 0});
|
||||
const [stickerDataVersion, setStickerDataVersion] = useState(0);
|
||||
const permissionVersion = useSyncExternalStore(Permission.subscribe.bind(Permission), () => Permission.version);
|
||||
const {shouldAnimate: shouldAnimateStickerPreview} = useStickerAnimation();
|
||||
@@ -138,13 +139,26 @@ export const StickersPicker = observer(
|
||||
allUpsell.accessibleItems,
|
||||
renderedStickers,
|
||||
);
|
||||
const zoomLevel = Accessibility.zoomLevel;
|
||||
const gridColumns = useMemo(() => getStickerGridColumns(viewportSize.width), [viewportSize.width, zoomLevel]);
|
||||
const previousGridColumnsRef = useRef(gridColumns);
|
||||
useLayoutEffect(() => {
|
||||
if (previousGridColumnsRef.current === gridColumns) {
|
||||
return;
|
||||
}
|
||||
previousGridColumnsRef.current = gridColumns;
|
||||
setHoveredSticker(null);
|
||||
setSelectedRow(-1);
|
||||
setSelectedColumn(-1);
|
||||
setShouldScrollOnSelection(false);
|
||||
}, [gridColumns]);
|
||||
const pickerRows = useVirtualRows(
|
||||
searchTerm,
|
||||
renderedStickers,
|
||||
favoriteStickers,
|
||||
frequentlyUsedStickers,
|
||||
stickersByGuildId,
|
||||
STICKERS_PER_ROW,
|
||||
gridColumns,
|
||||
);
|
||||
const hasNoStickersAtAll = allItems.length === 0;
|
||||
const isSearching = searchTerm.trim().length > 0;
|
||||
@@ -198,12 +212,8 @@ export const StickersPicker = observer(
|
||||
}
|
||||
return {stickerRowIndexes: indexes, stickerRowStarts: starts, categoryRowIndexes: categories};
|
||||
}, [pickerRows]);
|
||||
const zoomLevel = Accessibility.zoomLevel;
|
||||
const remScale = getAppRemScale();
|
||||
const stickerRowHeight = useMemo(
|
||||
() => getStickerRowHeight(listMetrics.gridWidth, STICKERS_PER_ROW, remScale),
|
||||
[listMetrics.gridWidth, remScale, zoomLevel],
|
||||
);
|
||||
const stickerRowHeight = useMemo(() => getFixedStickerRowHeight(remScale), [remScale, zoomLevel]);
|
||||
const rowOffsets = useMemo(() => {
|
||||
const rowKinds = pickerRows.map((row): StickerRowKind => row.type);
|
||||
return buildStickerRowOffsets(rowKinds, {remScale, stickerRowHeight, sectionGap: STICKER_SECTION_GAP});
|
||||
@@ -219,11 +229,8 @@ export const StickersPicker = observer(
|
||||
rowListNode.getBoundingClientRect().top - scrollerNode.getBoundingClientRect().top + scrollerNode.scrollTop,
|
||||
);
|
||||
const viewportHeight = scrollerNode.clientHeight;
|
||||
const gridWidth = rowListNode.clientWidth;
|
||||
setListMetrics((current) =>
|
||||
current.origin === origin && current.viewportHeight === viewportHeight && current.gridWidth === gridWidth
|
||||
? current
|
||||
: {origin, viewportHeight, gridWidth},
|
||||
current.origin === origin && current.viewportHeight === viewportHeight ? current : {origin, viewportHeight},
|
||||
);
|
||||
});
|
||||
const rowWindow = useMemo(
|
||||
@@ -394,7 +401,8 @@ export const StickersPicker = observer(
|
||||
row={row}
|
||||
handleHover={handleHover}
|
||||
handleSelect={handleStickerSelect}
|
||||
gridColumns={STICKERS_PER_ROW}
|
||||
gridColumns={gridColumns}
|
||||
cellTrackWidth={STICKER_GRID_TRACK_WIDTH}
|
||||
selectedRow={selectedRow}
|
||||
selectedColumn={selectedColumn}
|
||||
stickerRowIndex={stickerRowIndexes[rowIndex]!}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import {getRemScaleForDocument} from '@app/features/theme/layout/RemFromPx';
|
||||
|
||||
export const STICKERS_PER_ROW = 4;
|
||||
export const STICKERS_PER_ROW_MOBILE = 5;
|
||||
export const STICKER_CATEGORY_HEADER_HEIGHT = 32;
|
||||
export const STICKER_SECTION_GAP = 12;
|
||||
export const STICKER_GRID_TRACK_WIDTH = 120;
|
||||
|
||||
const STICKER_CATEGORY_HEADER_GAP = 8;
|
||||
const STICKER_GRID_GAP = 8;
|
||||
@@ -23,6 +26,20 @@ export interface StickerRowWindow {
|
||||
lastRow: number;
|
||||
}
|
||||
|
||||
export function getStickerGridColumns(containerWidth: number): number {
|
||||
if (containerWidth <= 0) {
|
||||
return STICKERS_PER_ROW;
|
||||
}
|
||||
const remScale = getRemScaleForDocument(typeof document === 'undefined' ? null : document);
|
||||
const trackWidth = STICKER_GRID_TRACK_WIDTH * remScale;
|
||||
const gap = STICKER_GRID_GAP * remScale;
|
||||
return Math.max(1, Math.floor((containerWidth + gap) / (trackWidth + gap)));
|
||||
}
|
||||
|
||||
export function getFixedStickerRowHeight(remScale: number): number {
|
||||
return (STICKER_GRID_TRACK_WIDTH + STICKER_GRID_BLOCK_END_PADDING) * remScale;
|
||||
}
|
||||
|
||||
export function getStickerRowHeight(gridWidth: number, gridColumns: number, remScale: number): number {
|
||||
if (!(gridWidth > 0) || gridColumns <= 0) {
|
||||
return 0;
|
||||
|
||||
@@ -20,6 +20,11 @@
|
||||
padding: 0 0 0.5rem;
|
||||
}
|
||||
|
||||
.stickerGridFixedTrack {
|
||||
grid-auto-flow: column;
|
||||
justify-content: start;
|
||||
}
|
||||
|
||||
.stickerButton {
|
||||
position: relative;
|
||||
display: flex;
|
||||
|
||||
@@ -27,6 +27,7 @@ interface VirtualRowRendererProps {
|
||||
handleHover: (sticker: GuildSticker | null, row?: number, column?: number) => void;
|
||||
handleSelect: (sticker: GuildSticker, shiftKey?: boolean) => void;
|
||||
gridColumns?: number;
|
||||
cellTrackWidth?: number;
|
||||
selectedRow: number;
|
||||
selectedColumn: number;
|
||||
stickerRowIndex: number;
|
||||
@@ -126,6 +127,7 @@ const VirtualRowRendererBase: React.FC<VirtualRowRendererProps> = React.memo(
|
||||
handleHover,
|
||||
handleSelect,
|
||||
gridColumns = 4,
|
||||
cellTrackWidth,
|
||||
selectedRow,
|
||||
selectedColumn,
|
||||
stickerRowIndex,
|
||||
@@ -220,11 +222,14 @@ const VirtualRowRendererBase: React.FC<VirtualRowRendererProps> = React.memo(
|
||||
);
|
||||
}
|
||||
if (row.type === 'sticker-row') {
|
||||
const hasFixedTrack = cellTrackWidth != null && cellTrackWidth > 0;
|
||||
return (
|
||||
<div
|
||||
className={styles.stickerGrid}
|
||||
className={hasFixedTrack ? `${styles.stickerGrid} ${styles.stickerGridFixedTrack}` : styles.stickerGrid}
|
||||
style={{
|
||||
gridTemplateColumns: `repeat(${gridColumns}, minmax(0, 1fr))`,
|
||||
gridTemplateColumns: hasFixedTrack
|
||||
? `repeat(auto-fill, ${remFromPx(cellTrackWidth)})`
|
||||
: `repeat(${gridColumns}, minmax(0, 1fr))`,
|
||||
}}
|
||||
data-flx="channel.sticker-picker.virtual-row.virtual-row-renderer-base.sticker-grid"
|
||||
>
|
||||
@@ -286,6 +291,7 @@ interface VirtualRowWrapperProps {
|
||||
handleHover: (sticker: GuildSticker | null, row?: number, column?: number) => void;
|
||||
handleSelect: (sticker: GuildSticker, shiftKey?: boolean) => void;
|
||||
gridColumns?: number;
|
||||
cellTrackWidth?: number;
|
||||
selectedRow: number;
|
||||
selectedColumn: number;
|
||||
stickerRowIndex: number;
|
||||
@@ -300,6 +306,7 @@ export const VirtualRowWrapper: React.FC<VirtualRowWrapperProps> = observer(
|
||||
handleHover,
|
||||
handleSelect,
|
||||
gridColumns,
|
||||
cellTrackWidth,
|
||||
selectedRow,
|
||||
selectedColumn,
|
||||
stickerRowIndex,
|
||||
@@ -313,6 +320,7 @@ export const VirtualRowWrapper: React.FC<VirtualRowWrapperProps> = observer(
|
||||
handleHover={handleHover}
|
||||
handleSelect={handleSelect}
|
||||
gridColumns={gridColumns}
|
||||
cellTrackWidth={cellTrackWidth}
|
||||
selectedRow={selectedRow}
|
||||
selectedColumn={selectedColumn}
|
||||
stickerRowIndex={stickerRowIndex}
|
||||
|
||||
Reference in new issue
Block a user