fix(theme): keep legacy appearance scoped

Co-authored-by: Kenny Lopez <klopez4212@gmail.com>
Signed-off-by: Kenny Lopez <klopez4212@gmail.com>
This commit is contained in:
Hardworking Honey
2026-08-12 13:26:27 +01:00
co-authored by Kenny Lopez
parent d3ae4eb648
commit 7e06a5cb1c
4 changed files with 38 additions and 9 deletions
@@ -80,7 +80,10 @@ export function CommunityThemeController() {
useLayoutEffect(() => {
if (!pubkey || !relayUrl) return;
const legacyFallback = initialPreferenceRef.current;
const legacyFallback = communityThemeScopeFallback(
hasMigratedCommunityTheme(pubkey),
initialPreferenceRef.current,
);
const local = readCommunityThemePreference(
pubkey,
relayUrl,
@@ -90,10 +93,7 @@ export function CommunityThemeController() {
// Preserve the user's existing global appearance the first time this
// feature sees their current community. Later missing/malformed target
// records use the stable default so the previous community never leaks.
const fallback = communityThemeScopeFallback(
hasMigratedCommunityTheme(pubkey),
initialPreferenceRef.current,
);
const fallback = legacyFallback;
const scopedPreference = dirty ?? local ?? fallback;
scopedPreferenceRef.current = scopedPreference;
applyPreference(scopedPreference);
@@ -110,7 +110,10 @@ export function CommunityThemeController() {
useEffect(() => {
if (!pubkey || !relayUrl) return;
const scope = `${pubkey}:${relayUrl}`;
const legacyFallback = initialPreferenceRef.current;
const legacyFallback = communityThemeScopeFallback(
hasMigratedCommunityTheme(pubkey),
initialPreferenceRef.current,
);
scopeRef.current = scope;
lastRemoteRef.current = { createdAt: 0, eventId: "" };
const manager = new CommunityThemeSyncManager(
@@ -247,7 +250,10 @@ export function CommunityThemeController() {
const stored = readCommunityThemePreference(
pubkey,
relayUrl,
initialPreferenceRef.current,
communityThemeScopeFallback(
hasMigratedCommunityTheme(pubkey),
initialPreferenceRef.current,
),
);
if (stored && sameCommunityThemePreference(stored, preference)) return;
scopedPreferenceRef.current = preference;
@@ -86,6 +86,29 @@ test("older theme records inherit the pre-migration appearance controls", () =>
});
});
test("later legacy records use stable defaults instead of a prior community", () => {
const priorCommunity = {
...DEFAULT_COMMUNITY_THEME,
glassBackground: true,
glassOpacity: 42,
prominentActiveTab: true,
};
const olderRecord = {
version: 1,
theme: "houston",
accent: "#a855f7",
followSystem: false,
};
assert.deepEqual(
parseCommunityThemePreference(
olderRecord,
communityThemeScopeFallback(true, priorCommunity),
),
{ ...DEFAULT_COMMUNITY_THEME, ...olderRecord },
);
});
test("appearance equality includes glass and prominent-tab choices", () => {
assert.equal(
sameCommunityThemePreference(DEFAULT_COMMUNITY_THEME, {
@@ -12,7 +12,7 @@ const defaultCommunityGlassBackground = false;
const defaultCommunityGlassOpacity = 65;
const minCommunityGlassOpacity = 30;
const maxCommunityGlassOpacity = 90;
const defaultCommunityProminentActiveTab = true;
const defaultCommunityProminentActiveTab = false;
const defaultCommunityTheme = CommunityThemePreference(
theme: 'buzz',
accent: '#3b82f6',
@@ -34,7 +34,7 @@ void main() {
expect(preference.glassBackground, isFalse);
expect(preference.glassOpacity, 65);
expect(preference.prominentActiveTab, isTrue);
expect(preference.prominentActiveTab, isFalse);
expect(preference.toJson(), containsPair('glassOpacity', 65));
});