perf(app): stop per-frame style recalculation in skeletons and member list (#1681)

This commit is contained in:
Hampus authored and GitHub committed 2026-08-16 22:00:10 +02:00
1 parent 170ca805c5
commit 438f11adda
11 files changed
+434 -93

No files matched your search

@@ -24,6 +24,7 @@ import {
CompassIcon,
DownloadSimpleIcon,
type Icon,
type IconWeight,
PlusIcon,
QuestionMarkIcon,
StarIcon,
@@ -118,7 +119,15 @@ const InlineDMPlaceholder = ({selected, unread}: {readonly selected: boolean; re
</flx-app-guild-rail-skeleton-item>
);
const RailActionButton = ({icon: Icon, selected = false}: {readonly icon: Icon; readonly selected?: boolean}) => (
const RailActionButton = ({
icon: Icon,
selected = false,
weight = 'bold',
}: {
readonly icon: Icon;
readonly selected?: boolean;
readonly weight?: IconWeight;
}) => (
<flx-app-guild-rail-skeleton-item
className={flxElementClassName(styles.item)}
data-selected={selectedAttribute(selected)}
@@ -129,7 +138,7 @@ const RailActionButton = ({icon: Icon, selected = false}: {readonly icon: Icon;
data-flx="app.skeleton.guild-rail-skeleton.rail-action-button.action-icon"
>
<Icon
weight="bold"
weight={weight}
className={styles.actionIconGlyph}
data-flx="app.skeleton.guild-rail-skeleton.rail-action-button.icon"
/>
@@ -578,6 +587,7 @@ export const GuildRailSkeleton: React.FC<GuildRailSkeletonProps> = ({
{discoveryVisible && (
<RailActionButton
icon={CompassIcon}
weight="fill"
selected={isDiscoverySelected}
data-flx="app.skeleton.guild-rail-skeleton.rail-action-button"
/>
@@ -1,11 +1,5 @@
/* SPDX-License-Identifier: AGPL-3.0-or-later */
@property --skeleton-shimmer-position {
syntax: '<percentage>';
inherits: true;
initial-value: -150%;
}
.skeleton {
--skeleton-opacity: var(--skeleton-opacity-default, 0.45);
--skeleton-width: 100%;
@@ -13,13 +7,13 @@
background-color: var(--background-modifier-accent);
background-image: linear-gradient(
105deg,
transparent 46%,
transparent 0%,
color-mix(in srgb, var(--text-primary) 7%, transparent) 50%,
transparent 54%
transparent 100%
);
background-size: 200vw 100%;
background-position: var(--skeleton-shimmer-position) 0;
background-attachment: fixed;
background-size: 200% 100%;
background-position: -50% 0;
animation: skeleton-shimmer 3.2s linear infinite;
opacity: var(--skeleton-opacity);
pointer-events: none;
user-select: none;
@@ -30,35 +24,25 @@
max-width: 100%;
}
:global(html):has(.skeleton) {
animation: skeleton-shimmer 3.2s ease-in-out infinite;
}
@keyframes skeleton-shimmer {
from {
--skeleton-shimmer-position: -150%;
background-position: -50% 0;
}
to {
--skeleton-shimmer-position: 150%;
background-position: 150% 0;
}
}
@media (prefers-reduced-motion: reduce) {
:global(html):has(.skeleton) {
animation: none;
}
.skeleton {
animation: none;
background-image: none;
}
}
:global(html.reduced-motion):has(.skeleton) {
animation: none;
}
:global(html.reduced-motion) .skeleton {
animation: none;
background-image: none;
}
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {clearRemScaleCache} from '@app/features/theme/layout/RemFromPx';
import type {NativePlatform} from '@app/features/ui/utils/NativeUtils';
import {useLayoutEffect} from 'react';
@@ -8,8 +9,10 @@ export function usePlatformClasses(platform: NativePlatform, isNative: boolean):
const htmlNode = document.documentElement;
const platformClasses = [isNative ? 'platform-native' : 'platform-web', `platform-${platform}`];
htmlNode.classList.add(...platformClasses);
clearRemScaleCache();
return () => {
htmlNode.classList.remove(...platformClasses);
clearRemScaleCache();
};
}, [isNative, platform]);
}