Add UI Customization Panel with full color theming

- New "Interfaccia" panel with color picker (HSV + hex/RGB/alpha + 30 presets)
- Profile background customization tab
- Accent color propagates via CSS variables to: card headers/tabs,
  context menus, Button dark/primary/gray variants, InfoStand panels,
  toolbar, room tools, purse, .btn-primary/.btn-dark CSS classes
- All elements use var(--name, fallback) for zero visual change when default
- Settings persisted in localStorage
- Added react-colorful dependency
- Added ui-config.json with header images config keys
This commit is contained in:
medievalshell
2026-03-18 20:11:40 +01:00
committed by simoleo89
parent ae4ecc42f0
commit ea35f19940
25 changed files with 3192 additions and 97 deletions
@@ -0,0 +1,52 @@
import { FC, useCallback, useMemo } from 'react';
import { GetConfigurationValue, useUiSettings } from '../../api';
export const InterfaceImageTabView: FC<{}> = () =>
{
const { settings, updateSettings } = useUiSettings();
const imageCount = useMemo(() =>
{
return GetConfigurationValue<number>('ui.header.images.count', 30);
}, []);
const baseUrl = useMemo(() =>
{
return GetConfigurationValue<string>('ui.header.images.url', 'https://image.webbo.city/image/headerImage/image{id}.gif');
}, []);
const images = useMemo(() =>
{
const result: string[] = [];
for(let i = 1; i <= imageCount; i++)
{
result.push(baseUrl.replace('{id}', String(i)));
}
return result;
}, [ imageCount, baseUrl ]);
const onImageSelect = useCallback((url: string) =>
{
updateSettings({
colorMode: 'image',
headerImageUrl: url
});
}, [ updateSettings ]);
return (
<div className="grid grid-cols-8 gap-1 p-2 overflow-auto max-h-[400px]">
{ images.map((url, i) => (
<div
key={ i }
className={ `w-[75px] h-[75px] rounded cursor-pointer border-2 transition-all hover:scale-105 ${ (settings.colorMode === 'image' && settings.headerImageUrl === url) ? 'border-white shadow-lg' : 'border-transparent' }` }
style={ {
backgroundImage: `url(${ url })`,
backgroundSize: 'cover',
backgroundPosition: 'center'
} }
onClick={ () => onImageSelect(url) }
/>
)) }
</div>
);
};