mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-20 15:36:18 +00:00
🆙 Redone the avatar editor
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
import { IPartColor } from '@nitrots/nitro-renderer';
|
||||
import { FC, useCallback, useMemo, useRef } from 'react';
|
||||
import { ColorUtils, GetClubMemberLevel, IAvatarEditorCategory } from '../../../api';
|
||||
import { useAvatarEditor } from '../../../hooks';
|
||||
|
||||
const findNearestColor = (hex: string, colors: IPartColor[]): IPartColor | null =>
|
||||
{
|
||||
const r = parseInt(hex.slice(1, 3), 16);
|
||||
const g = parseInt(hex.slice(3, 5), 16);
|
||||
const b = parseInt(hex.slice(5, 7), 16);
|
||||
const maxLevel = GetClubMemberLevel();
|
||||
let nearest: IPartColor | null = null;
|
||||
let minDist = Infinity;
|
||||
|
||||
for(const color of colors)
|
||||
{
|
||||
if(color.clubLevel > maxLevel) continue;
|
||||
|
||||
const cr = (color.rgb >> 16) & 0xFF;
|
||||
const cg = (color.rgb >> 8) & 0xFF;
|
||||
const cb = color.rgb & 0xFF;
|
||||
const dist = (r - cr) ** 2 + (g - cg) ** 2 + (b - cb) ** 2;
|
||||
|
||||
if(dist < minDist) { minDist = dist; nearest = color; }
|
||||
}
|
||||
|
||||
return nearest;
|
||||
};
|
||||
|
||||
export const AvatarEditorAdvancedColorView: FC<{
|
||||
category: IAvatarEditorCategory;
|
||||
paletteIndex: number;
|
||||
}> = ({ category, paletteIndex }) =>
|
||||
{
|
||||
const { selectedColorParts = null, selectEditorColor = null } = useAvatarEditor();
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const selectedColor = useMemo(() =>
|
||||
{
|
||||
if(!selectedColorParts?.[category?.setType]?.[paletteIndex]) return null;
|
||||
|
||||
return selectedColorParts[category.setType][paletteIndex];
|
||||
}, [ category, selectedColorParts, paletteIndex ]);
|
||||
|
||||
const hexColor = useMemo(() =>
|
||||
ColorUtils.makeColorNumberHex((selectedColor?.rgb ?? 0) & 0xFFFFFF),
|
||||
[ selectedColor ]);
|
||||
|
||||
const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
{
|
||||
const colors = category?.colorItems?.[paletteIndex];
|
||||
|
||||
if(!colors) return;
|
||||
|
||||
const nearest = findNearestColor(e.target.value, colors);
|
||||
|
||||
if(nearest) selectEditorColor(category.setType, paletteIndex, nearest.id);
|
||||
}, [ category, paletteIndex, selectEditorColor ]);
|
||||
|
||||
return (
|
||||
<div className="flex h-full p-1.5">
|
||||
<div
|
||||
className="flex-1 rounded-lg cursor-pointer relative border-2 border-white/20 overflow-hidden"
|
||||
style={{ backgroundColor: hexColor }}
|
||||
onClick={ () => inputRef.current?.click() }
|
||||
>
|
||||
<input
|
||||
ref={ inputRef }
|
||||
type="color"
|
||||
value={ hexColor }
|
||||
onChange={ handleChange }
|
||||
className="absolute opacity-0 inset-0 w-full h-full cursor-pointer"
|
||||
/>
|
||||
<div className="absolute bottom-0 left-0 right-0 py-1 text-center bg-black/40">
|
||||
<span className="text-xs font-mono font-bold text-white">
|
||||
{ hexColor.toUpperCase() }
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ColorConverter, IPartColor } from '@nitrots/nitro-renderer';
|
||||
import { FC } from 'react';
|
||||
import { GetConfigurationValue } from '../../../api';
|
||||
import { GetClubMemberLevel, GetConfigurationValue } from '../../../api';
|
||||
import { LayoutCurrencyIcon, LayoutGridItemProps } from '../../../common';
|
||||
import { InfiniteGrid } from '../../../layout';
|
||||
|
||||
@@ -16,9 +16,10 @@ export const AvatarEditorPaletteSetItem: FC<{
|
||||
if(!partColor) return null;
|
||||
|
||||
const isHC = !GetConfigurationValue<boolean>('hc.disabled', false) && (partColor.clubLevel > 0);
|
||||
const isLocked = isHC && (GetClubMemberLevel() < partColor.clubLevel);
|
||||
|
||||
return (
|
||||
<InfiniteGrid.Item itemHighlight className="clear-bg" itemActive={ isSelected } itemColor={ ColorConverter.int2rgb(partColor.rgb) } { ...rest }>
|
||||
<InfiniteGrid.Item itemHighlight className={ `clear-bg aspect-square${ isLocked ? ' opacity-50' : '' }` } itemActive={ isSelected } itemColor={ ColorConverter.int2rgb(partColor.rgb) } { ...rest }>
|
||||
{ isHC && <LayoutCurrencyIcon className="absolute inset-e-1 bottom-1" type="hc" /> }
|
||||
</InfiniteGrid.Item>
|
||||
);
|
||||
|
||||
@@ -24,7 +24,7 @@ export const AvatarEditorPaletteSetView: FC<{
|
||||
};
|
||||
|
||||
return (
|
||||
<InfiniteGrid<IPartColor> columnCount={ columnCount } itemRender={ (item: IPartColor) =>
|
||||
<InfiniteGrid<IPartColor> columnCount={ columnCount } estimateSize={ 18 } squareItems itemRender={ (item: IPartColor) =>
|
||||
{
|
||||
if(!item) return null;
|
||||
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export * from './AvatarEditorAdvancedColorView';
|
||||
export * from './AvatarEditorPaletteSetItemView';
|
||||
export * from './AvatarEditorPaletteSetView';
|
||||
|
||||
Reference in New Issue
Block a user