fix: theme preset persistence, page transition flash, and wheel LED jank

- ThemeTab: auto-save presets to server on apply so they persist across navigation
- PageLoader: add bg-dark-950 to prevent transparent flash during lazy-load transitions
- FortuneWheel: replace React state-based LED animation (10 re-renders/sec) with pure CSS @keyframes
This commit is contained in:
c0mrade
2026-02-06 02:12:13 +03:00
parent 562ab7abf7
commit f54ad4eb1f
3 changed files with 90 additions and 93 deletions

View File

@@ -92,40 +92,6 @@ export function ThemeTab() {
const hasUnsavedChanges = !colorsEqual(draftColors, savedColorsRef.current);
// Update a single color in the draft and apply preview instantly
const updateDraftColor = useCallback(
(key: keyof ThemeColors, value: string) => {
setDraftColors((prev) => {
const next = { ...prev, [key]: value };
applyThemeColors(next);
queryClient.setQueryData(['theme-colors'], next);
return next;
});
},
[queryClient],
);
// Apply a full preset to draft
const applyPreset = useCallback(
(colors: Partial<ThemeColors>) => {
setDraftColors((prev) => {
const next = { ...prev, ...colors };
applyThemeColors(next);
queryClient.setQueryData(['theme-colors'], next);
return next;
});
},
[queryClient],
);
// Cancel: revert draft to saved
const handleCancel = useCallback(() => {
const saved = savedColorsRef.current;
setDraftColors(saved);
applyThemeColors(saved);
queryClient.setQueryData(['theme-colors'], saved);
}, [queryClient]);
// Mutations
const updateColorsMutation = useMutation({
mutationFn: themeColorsApi.updateColors,
@@ -183,6 +149,42 @@ export function ThemeTab() {
},
});
// Update a single color in the draft and apply preview instantly
const updateDraftColor = useCallback(
(key: keyof ThemeColors, value: string) => {
setDraftColors((prev) => {
const next = { ...prev, [key]: value };
applyThemeColors(next);
queryClient.setQueryData(['theme-colors'], next);
return next;
});
},
[queryClient],
);
// Apply a full preset and auto-save to server
const applyPreset = useCallback(
(colors: Partial<ThemeColors>) => {
setDraftColors((prev) => {
const next = { ...prev, ...colors };
applyThemeColors(next);
queryClient.setQueryData(['theme-colors'], next);
// Auto-save preset to server so it persists across navigation
updateColorsMutation.mutate(next);
return next;
});
},
[queryClient, updateColorsMutation],
);
// Cancel: revert draft to saved
const handleCancel = useCallback(() => {
const saved = savedColorsRef.current;
setDraftColors(saved);
applyThemeColors(saved);
queryClient.setQueryData(['theme-colors'], saved);
}, [queryClient]);
return (
<div className="space-y-6">
{/* Theme toggles */}
@@ -416,17 +418,21 @@ export function ThemeTab() {
</button>
</>
)}
<button
onClick={() => resetColorsMutation.mutate()}
disabled={resetColorsMutation.isPending}
className="rounded-xl bg-dark-700 px-4 py-2 text-sm text-dark-300 transition-colors hover:bg-dark-600 disabled:opacity-50"
>
{t('admin.settings.resetAllColors')}
</button>
</div>
</div>
)}
</div>
{/* Reset all colors */}
<div className="flex justify-end">
<button
onClick={() => resetColorsMutation.mutate()}
disabled={resetColorsMutation.isPending}
className="rounded-xl bg-dark-700 px-4 py-2 text-sm text-dark-300 transition-colors hover:bg-dark-600 disabled:opacity-50"
>
{t('admin.settings.resetAllColors')}
</button>
</div>
</div>
);
}