feat: UI color theming system with live preview, presets and server sync

- RGBA color picker with live preview (debounce 50ms)
- 30 preset colors + 12 theme presets (Ocean, Forest, Sunset, Royal, etc.)
- Header image selection from configurable image library
- Export/Import theme as JSON via clipboard
- CSS variable theming across all UI elements: NitroCard headers/tabs,
  context menus, buttons (primary/dark/gray), InfoStand, toolbar,
  room tools, purse, progress bars, sliders
- All elements use var(--name, fallback) for zero visual change when default
- Smooth 0.3s CSS transitions on theme change
- Server-side persistence via WebSocket (packets 10047/10048)
- Integrated Color/Image tabs into BackgroundsView panel
- All strings use LocalizeText() for i18n support
- Settings persisted in localStorage + server sync with 1s debounce
- Added react-colorful dependency
This commit is contained in:
Life
2026-03-22 21:39:44 +01:00
parent b73c0841f2
commit 9c2dccaad6
28 changed files with 774 additions and 70 deletions
+10 -8
View File
@@ -1,6 +1,6 @@
import { GetAssetManager, GetAvatarRenderManager, GetCommunication, GetConfiguration, GetLocalizationManager, GetRoomEngine, GetRoomSessionManager, GetSessionDataManager, GetSoundManager, GetStage, GetTexturePool, GetTicker, HabboWebTools, LegacyExternalInterface, LoadGameUrlEvent, NitroLogger, NitroVersion, PrepareRenderer } from '@nitrots/nitro-renderer';
import { FC, useEffect, useState } from 'react';
import { GetUIVersion } from './api';
import { GetUIVersion, UiSettingsProvider } from './api';
import { Base } from './common';
import { LoadingView } from './components/loading/LoadingView';
import { MainView } from './components/MainView';
@@ -90,12 +90,14 @@ export const App: FC<{}> = props =>
}, []);
return (
<Base fit overflow="hidden" className={ !(window.devicePixelRatio % 1) && 'image-rendering-pixelated' }>
{ !isReady &&
<LoadingView /> }
{ isReady && <MainView /> }
<ReconnectView />
<Base id="draggable-windows-container" />
</Base>
<UiSettingsProvider>
<Base fit overflow="hidden" className={ !(window.devicePixelRatio % 1) && 'image-rendering-pixelated' }>
{ !isReady &&
<LoadingView /> }
{ isReady && <MainView /> }
<ReconnectView />
<Base id="draggable-windows-container" />
</Base>
</UiSettingsProvider>
);
};