fix(wave-3): audit fixes — ACL guards, presence, moderation, theming perf
Wave-3 bug-hunt fixes (findings in LOTUS_TODO), reviewed + gate-green: - 🔴 ACL editor [H1–H4]: block saving an empty allow-list (was a one-click federation brick), warn on self-ban (case-insensitive glob match of mx.getDomain() vs allow/deny), accept real globs (1.2.3.*, *.evil.*), and gate Save behind a confirm dialog. - 🔴 [P1] room context menu no longer acts on the wrong room after a live reorder (key by roomId, not list index). 🔴 [P2] status writes no longer force presence to online over Invisible/DND (shared presenceStateFromSetting). - 🟠 [P3] timed mutes restored on boot; [P4] custom-status auto-clear now fires (always-mounted StatusExpiryMonitor); [P5] timezone also PUT to the m.tz profile field so it's visible to others; [H6] RoomInsights single-pass min/max (was Math.min(...spread) stack overflow); [H7/H8] mod-log labels. - 🟡 [P6/P7] favorites collapse+filter, [P8] charCount reset, [P9] DM preview refresh on decrypt; theming [T-P1] lazy decorations, [T-P2] drop the redundant always-on body animation, [T-P4] live useReducedMotion, [T-P5] decoration key. - NATIVE-CINNY LAW: notification presets + Powers permissions use folds icons. DEFERRED: [H5] invite-QR is fetched from api.qrserver.com (third-party leak); local generation needs a bundled QR lib (not added). tsc/eslint/prettier clean, build OK, 677 tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,7 @@ import { CreateTab } from './sidebar/CreateTab';
|
||||
import { useSetting } from '../../state/hooks/settings';
|
||||
import { settingsAtom } from '../../state/settings';
|
||||
import { useTheme, ThemeKind } from '../../hooks/useTheme';
|
||||
import { useReducedMotion } from '../../hooks/useReducedMotion';
|
||||
import { getChatBg } from '../../features/lotus/chatBackground';
|
||||
|
||||
export function SidebarNav() {
|
||||
@@ -34,6 +35,7 @@ export function SidebarNav() {
|
||||
const [pauseAnimations] = useSetting(settingsAtom, 'pauseAnimations');
|
||||
const theme = useTheme();
|
||||
const isDark = theme.kind === ThemeKind.Dark;
|
||||
const reduced = useReducedMotion();
|
||||
|
||||
// backdrop-filter only blurs content directly behind the element in the z-axis.
|
||||
// The sidebar is a flex sibling of the room view, so nothing sits behind it by default.
|
||||
@@ -53,17 +55,26 @@ export function SidebarNav() {
|
||||
}
|
||||
|
||||
const effectiveBg = chatBackground !== 'none' ? chatBackground : 'tactical';
|
||||
const bgStyle = getChatBg(effectiveBg, isDark, pauseAnimations);
|
||||
const bgStyle = getChatBg(effectiveBg, isDark, pauseAnimations || reduced);
|
||||
style.backgroundImage = (bgStyle.backgroundImage as string | undefined) ?? '';
|
||||
style.backgroundColor = (bgStyle.backgroundColor as string | undefined) ?? '';
|
||||
style.backgroundSize = (bgStyle.backgroundSize as string | undefined) ?? '';
|
||||
style.backgroundPosition = (bgStyle.backgroundPosition as string | undefined) ?? '';
|
||||
style.animation = (bgStyle.animation as string | undefined) ?? '';
|
||||
// Promote animated backgrounds to their own compositor layer so the browser
|
||||
// doesn't repaint the overlaid text/UI content on every animation frame.
|
||||
if (bgStyle.animation) {
|
||||
style.willChange = 'background-position, background-size';
|
||||
// The animated body mirror (animation + will-change) exists solely so the
|
||||
// glassmorphism sidebar can blur through document.body. When glass is OFF nothing
|
||||
// samples this layer, yet SidebarNav is always mounted, so writing an animated bg +
|
||||
// will-change here would leave a permanent invisible animated compositor layer
|
||||
// app-wide. Only mirror the animation when glass is on; the static background above
|
||||
// (needed by lotusTerminal / non-animated cases) is still written regardless.
|
||||
if (glassmorphismSidebar) {
|
||||
style.animation = (bgStyle.animation as string | undefined) ?? '';
|
||||
if (bgStyle.animation) {
|
||||
style.willChange = 'background-position, background-size';
|
||||
} else {
|
||||
style.removeProperty('will-change');
|
||||
}
|
||||
} else {
|
||||
style.removeProperty('animation');
|
||||
style.removeProperty('will-change');
|
||||
}
|
||||
|
||||
@@ -75,7 +86,7 @@ export function SidebarNav() {
|
||||
style.removeProperty('animation');
|
||||
style.removeProperty('will-change');
|
||||
};
|
||||
}, [glassmorphismSidebar, chatBackground, lotusTerminal, isDark, pauseAnimations]);
|
||||
}, [glassmorphismSidebar, chatBackground, lotusTerminal, isDark, pauseAnimations, reduced]);
|
||||
|
||||
return (
|
||||
<Sidebar className={classNames(glassmorphismSidebar && SidebarGlass)}>
|
||||
|
||||
Reference in New Issue
Block a user