From a1841c51a78887d92bc6e73cad3476a8b5edc2ad Mon Sep 17 00:00:00 2001 From: cyph3rasi Date: Wed, 15 Jul 2026 11:42:42 -0700 Subject: [PATCH] Prevent local admin profile media from blurring during NSFW node updates Hop-State: A_06FPE5MS0ZXE3ESZJJ27C98 Hop-Proposal: R_06FPE5KR2QGEVQD0MW8DSZR Hop-Task: T_06FPE564WJTQYM53WG3W8P8 Hop-Attempt: AT_06FPE564WKTFF688KW6DM80 --- src/app/admin/page.tsx | 7 +++++++ src/components/RightSidebar.tsx | 7 +++++-- src/lib/contexts/ConfigContext.tsx | 10 ++++++++-- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx index 98be888..a5b3e33 100644 --- a/src/app/admin/page.tsx +++ b/src/app/admin/page.tsx @@ -8,10 +8,12 @@ import { useToast } from '@/lib/contexts/ToastContext'; import { useAccentColor } from '@/lib/contexts/AccentColorContext'; import { getStorageProvider, MediaUploadError, uploadMediaFile } from '@/lib/stuffbox/browser-upload'; import { hasUnsavedChanges } from '@/lib/forms/dirty-state'; +import { useRuntimeConfig } from '@/lib/contexts/ConfigContext'; export default function AdminPage() { const { showToast } = useToast(); const { refreshAccentColor } = useAccentColor(); + const { setNodeNsfw } = useRuntimeConfig(); const [isAdmin, setIsAdmin] = useState(null); const [loading, setLoading] = useState(false); const [nodeSettings, setNodeSettings] = useState({ @@ -93,6 +95,11 @@ export default function AdminPage() { savedNodeSettingsRef.current = payload; const data = await res.json().catch(() => ({})); if (data.node) { + // Keep the global local-node classification and the sidebar's + // node payload in the same React batch. Otherwise profile + // media briefly sees "remote NSFW node on a safe local node" + // and applies a blur until the next full config refresh. + setNodeNsfw(data.node.isNsfw === true); window.dispatchEvent(new CustomEvent('synapsis:node-updated', { detail: data.node })); } showToast('Settings saved!', 'success'); diff --git a/src/components/RightSidebar.tsx b/src/components/RightSidebar.tsx index 67660a4..053e140 100644 --- a/src/components/RightSidebar.tsx +++ b/src/components/RightSidebar.tsx @@ -4,6 +4,7 @@ import { useState, useEffect } from 'react'; import Link from 'next/link'; import { AvatarImage } from './AvatarImage'; import { ProfileBanner } from './ProfileBanner'; +import { useRuntimeConfig } from '@/lib/contexts/ConfigContext'; interface Admin { handle: string; @@ -34,6 +35,8 @@ function formatNetworkTotal(value: number | undefined): string { } export function RightSidebar() { + const { config } = useRuntimeConfig(); + const localNodeIsNsfw = config?.isNsfw ?? false; const fallbackDescription = process.env.NEXT_PUBLIC_NODE_DESCRIPTION || 'A swarm social network node.'; const [nodeInfo, setNodeInfo] = useState({ name: process.env.NEXT_PUBLIC_NODE_NAME || 'Synapsis Node', @@ -138,7 +141,7 @@ export function RightSidebar() { {nodeInfo.bannerUrl && ( @@ -187,7 +190,7 @@ export function RightSidebar() { style={{ display: 'flex', alignItems: 'center', gap: '10px', textDecoration: 'none', color: 'inherit' }} >
- +
diff --git a/src/lib/contexts/ConfigContext.tsx b/src/lib/contexts/ConfigContext.tsx index b6087bf..712c7fa 100644 --- a/src/lib/contexts/ConfigContext.tsx +++ b/src/lib/contexts/ConfigContext.tsx @@ -1,6 +1,6 @@ 'use client'; -import { createContext, useContext, useEffect, useState, ReactNode } from 'react'; +import { createContext, useCallback, useContext, useEffect, useState, ReactNode } from 'react'; interface RuntimeConfig { domain: string; @@ -10,17 +10,23 @@ interface RuntimeConfig { interface ConfigContextType { config: RuntimeConfig | null; isLoading: boolean; + setNodeNsfw: (isNsfw: boolean) => void; } const ConfigContext = createContext({ config: null, isLoading: true, + setNodeNsfw: () => { }, }); export function ConfigProvider({ children }: { children: ReactNode }) { const [config, setConfig] = useState(null); const [isLoading, setIsLoading] = useState(true); + const setNodeNsfw = useCallback((isNsfw: boolean) => { + setConfig((current) => current ? { ...current, isNsfw } : current); + }, []); + useEffect(() => { // Fetch runtime config on mount fetch('/api/config') @@ -44,7 +50,7 @@ export function ConfigProvider({ children }: { children: ReactNode }) { }, []); return ( - + {children} );