Avatar editor updates
7
src/api/nitro/avatar/GetAvatarPalette.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { IPalette } from 'nitro-renderer';
|
||||||
|
import { GetAvatarRenderManager } from './GetAvatarRenderManager';
|
||||||
|
|
||||||
|
export function GetAvatarPalette(paletteId: number): IPalette
|
||||||
|
{
|
||||||
|
return GetAvatarRenderManager().structureData.getPalette(paletteId);
|
||||||
|
}
|
7
src/api/nitro/avatar/GetAvatarSetType.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { ISetType } from 'nitro-renderer';
|
||||||
|
import { GetAvatarRenderManager } from './GetAvatarRenderManager';
|
||||||
|
|
||||||
|
export function GetAvatarSetType(setType: string): ISetType
|
||||||
|
{
|
||||||
|
return GetAvatarRenderManager().structureData.getSetType(setType);
|
||||||
|
}
|
@ -1 +1,3 @@
|
|||||||
|
export * from './GetAvatarPalette';
|
||||||
export * from './GetAvatarRenderManager';
|
export * from './GetAvatarRenderManager';
|
||||||
|
export * from './GetAvatarSetType';
|
||||||
|
6
src/api/nitro/session/GetClubMemberLevel.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { GetSessionDataManager } from './GetSessionDataManager';
|
||||||
|
|
||||||
|
export function GetClubMemberLevel(): number
|
||||||
|
{
|
||||||
|
return GetSessionDataManager().clubLevel;
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
export * from './CanManipulateFurniture';
|
export * from './CanManipulateFurniture';
|
||||||
export * from './GetCanStandUp';
|
export * from './GetCanStandUp';
|
||||||
export * from './GetCanUseExpression';
|
export * from './GetCanUseExpression';
|
||||||
|
export * from './GetClubMemberLevel';
|
||||||
export * from './GetFurnitureDataForProductOffer';
|
export * from './GetFurnitureDataForProductOffer';
|
||||||
export * from './GetFurnitureDataForRoomObject';
|
export * from './GetFurnitureDataForRoomObject';
|
||||||
export * from './GetOwnPosture';
|
export * from './GetOwnPosture';
|
||||||
|
Before Width: | Height: | Size: 263 B After Width: | Height: | Size: 272 B |
Before Width: | Height: | Size: 146 B After Width: | Height: | Size: 236 B |
Before Width: | Height: | Size: 196 B After Width: | Height: | Size: 270 B |
Before Width: | Height: | Size: 135 B After Width: | Height: | Size: 196 B |
Before Width: | Height: | Size: 162 B After Width: | Height: | Size: 236 B |
Before Width: | Height: | Size: 137 B After Width: | Height: | Size: 228 B |
Before Width: | Height: | Size: 195 B After Width: | Height: | Size: 256 B |
Before Width: | Height: | Size: 122 B After Width: | Height: | Size: 208 B |
Before Width: | Height: | Size: 165 B After Width: | Height: | Size: 266 B |
Before Width: | Height: | Size: 164 B After Width: | Height: | Size: 257 B |
Before Width: | Height: | Size: 199 B After Width: | Height: | Size: 308 B |
@ -179,15 +179,14 @@
|
|||||||
|
|
||||||
&.clear-icon {
|
&.clear-icon {
|
||||||
background-image: url('../images/avatareditor/clear-icon.png');
|
background-image: url('../images/avatareditor/clear-icon.png');
|
||||||
width: 16px;
|
width: 27px;
|
||||||
height: 16px;
|
height: 27px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.ca-icon {
|
&.ca-icon {
|
||||||
background-image: url('../images/avatareditor/ca-icon.png');
|
background-image: url('../images/avatareditor/ca-icon.png');
|
||||||
width: 30px;
|
width: 25px;
|
||||||
height: 24px;
|
height: 25px;
|
||||||
background
|
|
||||||
|
|
||||||
&.selected {
|
&.selected {
|
||||||
background-image: url('../images/avatareditor/ca-selected-icon.png');
|
background-image: url('../images/avatareditor/ca-selected-icon.png');
|
||||||
@ -216,8 +215,8 @@
|
|||||||
|
|
||||||
&.cp-icon {
|
&.cp-icon {
|
||||||
background-image: url('../images/avatareditor/cp-icon.png');
|
background-image: url('../images/avatareditor/cp-icon.png');
|
||||||
width: 25px;
|
width: 30px;
|
||||||
height: 25px;
|
height: 24px;
|
||||||
|
|
||||||
&.selected {
|
&.selected {
|
||||||
background-image: url('../images/avatareditor/cp-selected-icon.png');
|
background-image: url('../images/avatareditor/cp-selected-icon.png');
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
.content-area {
|
.content-area {
|
||||||
padding-top: $container-padding-x;
|
padding-top: $container-padding-x;
|
||||||
padding-bottom: $container-padding-x;
|
padding-bottom: $container-padding-x;
|
||||||
|
resize: vertical;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
&.simple {
|
&.simple {
|
||||||
padding-left: ($container-padding-x + 25px);
|
padding-left: ($container-padding-x + 25px);
|
||||||
|
@ -4,11 +4,11 @@ import { NitroCardGridThemes, NitroCardGridViewProps } from './NitroCardGridView
|
|||||||
|
|
||||||
export const NitroCardGridView: FC<NitroCardGridViewProps> = props =>
|
export const NitroCardGridView: FC<NitroCardGridViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { columns = 5, theme = NitroCardGridThemes.THEME_DEFAULT, children = null } = props;
|
const { columns = 5, theme = NitroCardGridThemes.THEME_DEFAULT, className = '', children = null, ...rest } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NitroCardGridContextProvider value={ { theme } }>
|
<NitroCardGridContextProvider value={ { theme } }>
|
||||||
<div className={ `h-100 overflow-hidden nitro-card-grid ${ theme }` }>
|
<div className={ `h-100 overflow-hidden nitro-card-grid ${ theme } ${ className || '' }` } { ...rest }>
|
||||||
<div className={ `row row-cols-${ columns } align-content-start g-0 w-100 h-100 overflow-auto` }>
|
<div className={ `row row-cols-${ columns } align-content-start g-0 w-100 h-100 overflow-auto` }>
|
||||||
{ children }
|
{ children }
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
export interface NitroCardGridViewProps
|
import { DetailsHTMLAttributes } from 'react';
|
||||||
|
|
||||||
|
export interface NitroCardGridViewProps extends DetailsHTMLAttributes<HTMLDivElement>
|
||||||
{
|
{
|
||||||
columns?: number;
|
columns?: number;
|
||||||
theme?: string;
|
theme?: string;
|
||||||
|
@ -3,6 +3,9 @@
|
|||||||
max-height: 50px;
|
max-height: 50px;
|
||||||
|
|
||||||
.grid-item {
|
.grid-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
.nitro-avatar-editor {
|
.nitro-avatar-editor {
|
||||||
width: 600px;
|
width: 620px;
|
||||||
|
|
||||||
.content-area {
|
.content-area {
|
||||||
height: 330px;
|
min-height: 300px;
|
||||||
max-height: 330px;
|
height: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-item {
|
||||||
|
height: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.figure-preview-container {
|
.figure-preview-container {
|
||||||
@ -13,27 +17,53 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
|
||||||
.avatar-image {
|
|
||||||
margin: 45px auto 0;
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.arrow-container {
|
.arrow-container {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
padding: 0 10px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: space-between;
|
||||||
bottom: 12px;
|
bottom: 12px;
|
||||||
z-index: 3;
|
z-index: 5;
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.arrow-left-icon {
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.avatar-image {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 50px;
|
||||||
|
margin: 0 auto;
|
||||||
|
z-index: 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-spotlight {
|
||||||
|
position: absolute;
|
||||||
|
top: -10px;
|
||||||
|
width: 100%;
|
||||||
|
height: 305px;
|
||||||
|
margin: 0 auto;
|
||||||
|
background: transparent url('../../assets/images/avatareditor/spotlight.png') no-repeat center;
|
||||||
|
opacity: 0.3;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-shadow {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 15px;
|
||||||
|
width: 70px;
|
||||||
|
height: 30px;
|
||||||
|
margin: 0 auto;
|
||||||
|
border-radius: 100%;
|
||||||
|
background-color: rgba(0, 0, 0, 0.20);
|
||||||
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:after {
|
&:after {
|
||||||
@ -44,7 +74,8 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background-color: red;
|
background-color: $pale-sky;
|
||||||
|
box-shadow: 0 0 8px 2px rgba($white,.6);
|
||||||
transform: scale(2);
|
transform: scale(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,103 +1,91 @@
|
|||||||
import { AvatarEditorFigureCategory } from 'nitro-renderer';
|
import { AvatarDirectionAngle, AvatarEditorFigureCategory, UserFigureComposer } from 'nitro-renderer';
|
||||||
import { FC, useCallback, useEffect, useReducer, useState } from 'react';
|
import { FC, useCallback, useEffect, useState } from 'react';
|
||||||
import { GetSessionDataManager } from '../../api';
|
import { GetSessionDataManager } from '../../api';
|
||||||
import { AvatarEditorEvent } from '../../events/avatar-editor';
|
import { AvatarEditorEvent } from '../../events/avatar-editor';
|
||||||
|
import { SendMessageHook } from '../../hooks';
|
||||||
import { useUiEvent } from '../../hooks/events/ui/ui-event';
|
import { useUiEvent } from '../../hooks/events/ui/ui-event';
|
||||||
import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../layout';
|
import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../layout';
|
||||||
import { LocalizeText } from '../../utils/LocalizeText';
|
import { LocalizeText } from '../../utils/LocalizeText';
|
||||||
import { AvatarEditorViewProps } from './AvatarEditorView.types';
|
import { AvatarEditorViewProps } from './AvatarEditorView.types';
|
||||||
import { AvatarEditor } from './common/AvatarEditor';
|
import { AvatarEditorUtilities } from './common/AvatarEditorUtilities';
|
||||||
import { BodyModel } from './common/BodyModel';
|
import { BodyModel } from './common/BodyModel';
|
||||||
import { FigureData } from './common/FigureData';
|
import { FigureData } from './common/FigureData';
|
||||||
import { HeadModel } from './common/HeadModel';
|
import { HeadModel } from './common/HeadModel';
|
||||||
import { IAvatarEditorCategoryModel } from './common/IAvatarEditorCategoryModel';
|
import { IAvatarEditorCategoryModel } from './common/IAvatarEditorCategoryModel';
|
||||||
import { LegModel } from './common/LegModel';
|
import { LegModel } from './common/LegModel';
|
||||||
import { TorsoModel } from './common/TorsoModel';
|
import { TorsoModel } from './common/TorsoModel';
|
||||||
import { AvatarEditorContextProvider } from './context/AvatarEditorContext';
|
import { AvatarEditorFigurePreviewView } from './views/figure-preview/AvatarEditorFigurePreviewView';
|
||||||
import { AvatarEditorReducer, initialAvatarEditor } from './reducers/AvatarEditorReducer';
|
|
||||||
import { AvatarEditorModelView } from './views/model/AvatarEditorModelView';
|
import { AvatarEditorModelView } from './views/model/AvatarEditorModelView';
|
||||||
|
|
||||||
|
const DEFAULT_MALE_FIGURE: string = 'hr-100.hd-180-7.ch-215-66.lg-270-79.sh-305-62.ha-1002-70.wa-2007';
|
||||||
|
const DEFAULT_FEMALE_FIGURE: string = 'hr-515-33.hd-600-1.ch-635-70.lg-716-66-62.sh-735-68';
|
||||||
|
|
||||||
export const AvatarEditorView: FC<AvatarEditorViewProps> = props =>
|
export const AvatarEditorView: FC<AvatarEditorViewProps> = props =>
|
||||||
{
|
{
|
||||||
const [ isVisible, setIsVisible ] = useState(false);
|
const [ isVisible, setIsVisible ] = useState(false);
|
||||||
const [ avatarEditorState, dispatchAvatarEditorState ] = useReducer(AvatarEditorReducer, initialAvatarEditor);
|
const [ figures, setFigures ] = useState<Map<string, FigureData>>(null);
|
||||||
const [ avatarEditor, setAvatarEditor ] = useState<AvatarEditor>(null);
|
const [ figureData, setFigureData ] = useState<FigureData>(null);
|
||||||
const [ categories, setCategories ] = useState<Map<string, IAvatarEditorCategoryModel>>(null);
|
const [ categories, setCategories ] = useState<Map<string, IAvatarEditorCategoryModel>>(null);
|
||||||
const [ activeCategory, setActiveCategory ] = useState<IAvatarEditorCategoryModel>(null);
|
const [ activeCategory, setActiveCategory ] = useState<IAvatarEditorCategoryModel>(null);
|
||||||
|
const [ lastFigure, setLastFigure ] = useState<string>(null);
|
||||||
|
const [ lastGender, setLastGender ] = useState<string>(null);
|
||||||
|
const [ needsReset, setNeedsReset ] = useState(false);
|
||||||
const [ isInitalized, setIsInitalized ] = useState(false);
|
const [ isInitalized, setIsInitalized ] = useState(false);
|
||||||
|
|
||||||
const selectCategory = useCallback((name: string) =>
|
const selectCategory = useCallback((name: string) =>
|
||||||
{
|
{
|
||||||
|
if(!categories) return;
|
||||||
|
|
||||||
setActiveCategory(categories.get(name));
|
setActiveCategory(categories.get(name));
|
||||||
}, [ categories ]);
|
}, [ categories ]);
|
||||||
|
|
||||||
const resetCategories = useCallback((editor: AvatarEditor) =>
|
const resetCategories = useCallback(() =>
|
||||||
{
|
{
|
||||||
const categories = new Map();
|
const categories = new Map();
|
||||||
|
|
||||||
categories.set(AvatarEditorFigureCategory.GENERIC, new BodyModel(editor));
|
categories.set(AvatarEditorFigureCategory.GENERIC, new BodyModel());
|
||||||
categories.set(AvatarEditorFigureCategory.HEAD, new HeadModel(editor));
|
categories.set(AvatarEditorFigureCategory.HEAD, new HeadModel());
|
||||||
categories.set(AvatarEditorFigureCategory.TORSO, new TorsoModel(editor));
|
categories.set(AvatarEditorFigureCategory.TORSO, new TorsoModel());
|
||||||
categories.set(AvatarEditorFigureCategory.LEGS, new LegModel(editor));
|
categories.set(AvatarEditorFigureCategory.LEGS, new LegModel());
|
||||||
|
|
||||||
setCategories(categories);
|
setCategories(categories);
|
||||||
setActiveCategory(categories.get(AvatarEditorFigureCategory.GENERIC));
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const selectGender = useCallback((gender: string) =>
|
const setupFigures = useCallback(() =>
|
||||||
{
|
{
|
||||||
if(gender === avatarEditor.gender) return;
|
const figures: Map<string, FigureData> = new Map();
|
||||||
|
|
||||||
avatarEditor.gender = gender;
|
const maleFigure = new FigureData();
|
||||||
|
const femaleFigure = new FigureData();
|
||||||
|
|
||||||
resetCategories(avatarEditor);
|
maleFigure.loadAvatarData(DEFAULT_MALE_FIGURE, FigureData.MALE);
|
||||||
}, [ avatarEditor, resetCategories ]);
|
femaleFigure.loadAvatarData(DEFAULT_FEMALE_FIGURE, FigureData.FEMALE);
|
||||||
|
|
||||||
|
figures.set(FigureData.MALE, maleFigure);
|
||||||
|
figures.set(FigureData.FEMALE, femaleFigure);
|
||||||
|
|
||||||
|
setFigures(figures);
|
||||||
|
setFigureData(figures.get(FigureData.MALE));
|
||||||
|
}, []);
|
||||||
|
|
||||||
const loadAvatarInEditor = useCallback((figure: string, gender: string, reset: boolean = true) =>
|
const loadAvatarInEditor = useCallback((figure: string, gender: string, reset: boolean = true) =>
|
||||||
{
|
{
|
||||||
if(!avatarEditor) return;
|
gender = AvatarEditorUtilities.getGender(gender);
|
||||||
|
|
||||||
switch(gender)
|
let newFigureData = figureData;
|
||||||
|
|
||||||
|
if(gender !== newFigureData.gender) newFigureData = figures.get(gender);
|
||||||
|
|
||||||
|
if(figure !== newFigureData.getFigureString()) newFigureData.loadAvatarData(figure, gender);
|
||||||
|
|
||||||
|
if(newFigureData !== figureData) setFigureData(newFigureData);
|
||||||
|
|
||||||
|
if(reset)
|
||||||
{
|
{
|
||||||
case FigureData.MALE:
|
setLastFigure(figureData.getFigureString());
|
||||||
case 'm':
|
setLastGender(figureData.gender);
|
||||||
case 'M':
|
|
||||||
gender = FigureData.MALE;
|
|
||||||
break;
|
|
||||||
case FigureData.FEMALE:
|
|
||||||
case 'f':
|
|
||||||
case 'F':
|
|
||||||
gender = FigureData.FEMALE;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
gender = FigureData.MALE;
|
|
||||||
}
|
}
|
||||||
|
}, [ figures, figureData ]);
|
||||||
let update = false;
|
|
||||||
|
|
||||||
if(gender !== avatarEditor.gender)
|
|
||||||
{
|
|
||||||
avatarEditor.gender = gender;
|
|
||||||
|
|
||||||
update = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const figureData = avatarEditor.figureData;
|
|
||||||
|
|
||||||
if(!figureData) return;
|
|
||||||
|
|
||||||
if(figure !== figureData.getFigureString())
|
|
||||||
{
|
|
||||||
update = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
figureData.loadAvatarData(figure, gender);
|
|
||||||
|
|
||||||
if(update)
|
|
||||||
{
|
|
||||||
resetCategories(avatarEditor);
|
|
||||||
}
|
|
||||||
}, [ avatarEditor, resetCategories ]);
|
|
||||||
|
|
||||||
const onAvatarEditorEvent = useCallback((event: AvatarEditorEvent) =>
|
const onAvatarEditorEvent = useCallback((event: AvatarEditorEvent) =>
|
||||||
{
|
{
|
||||||
@ -105,12 +93,20 @@ export const AvatarEditorView: FC<AvatarEditorViewProps> = props =>
|
|||||||
{
|
{
|
||||||
case AvatarEditorEvent.SHOW_EDITOR:
|
case AvatarEditorEvent.SHOW_EDITOR:
|
||||||
setIsVisible(true);
|
setIsVisible(true);
|
||||||
|
setNeedsReset(true);
|
||||||
return;
|
return;
|
||||||
case AvatarEditorEvent.HIDE_EDITOR:
|
case AvatarEditorEvent.HIDE_EDITOR:
|
||||||
setIsVisible(false);
|
setIsVisible(false);
|
||||||
return;
|
return;
|
||||||
case AvatarEditorEvent.TOGGLE_EDITOR:
|
case AvatarEditorEvent.TOGGLE_EDITOR:
|
||||||
setIsVisible(prevValue => !prevValue);
|
setIsVisible(prevValue =>
|
||||||
|
{
|
||||||
|
const flag = !prevValue;
|
||||||
|
|
||||||
|
if(flag) setNeedsReset(true);
|
||||||
|
|
||||||
|
return flag;
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
@ -119,30 +115,92 @@ export const AvatarEditorView: FC<AvatarEditorViewProps> = props =>
|
|||||||
useUiEvent(AvatarEditorEvent.HIDE_EDITOR, onAvatarEditorEvent);
|
useUiEvent(AvatarEditorEvent.HIDE_EDITOR, onAvatarEditorEvent);
|
||||||
useUiEvent(AvatarEditorEvent.TOGGLE_EDITOR, onAvatarEditorEvent);
|
useUiEvent(AvatarEditorEvent.TOGGLE_EDITOR, onAvatarEditorEvent);
|
||||||
|
|
||||||
|
const clearFigure = useCallback(() =>
|
||||||
|
{
|
||||||
|
loadAvatarInEditor(figureData.getFigureStringWithFace(0, false), figureData.gender, false);
|
||||||
|
resetCategories();
|
||||||
|
}, [ figureData, loadAvatarInEditor, resetCategories ]);
|
||||||
|
|
||||||
|
const resetFigure = useCallback(() =>
|
||||||
|
{
|
||||||
|
loadAvatarInEditor(lastFigure, lastGender);
|
||||||
|
resetCategories();
|
||||||
|
}, [ lastFigure, lastGender, loadAvatarInEditor, resetCategories ]);
|
||||||
|
|
||||||
|
const rotateFigure = useCallback((direction: number) =>
|
||||||
|
{
|
||||||
|
if(direction < AvatarDirectionAngle.MIN_DIRECTION)
|
||||||
|
{
|
||||||
|
direction = (AvatarDirectionAngle.MAX_DIRECTION + (direction + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(direction > AvatarDirectionAngle.MAX_DIRECTION)
|
||||||
|
{
|
||||||
|
direction = (direction - (AvatarDirectionAngle.MAX_DIRECTION + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
figureData.direction = direction;
|
||||||
|
}, [ figureData ]);
|
||||||
|
|
||||||
|
const saveFigure = useCallback(() =>
|
||||||
|
{
|
||||||
|
SendMessageHook(new UserFigureComposer(figureData.gender, figureData.getFigureString()));
|
||||||
|
}, [ figureData ]);
|
||||||
|
|
||||||
|
const setGender = useCallback((gender: string) =>
|
||||||
|
{
|
||||||
|
gender = AvatarEditorUtilities.getGender(gender);
|
||||||
|
|
||||||
|
setFigureData(figures.get(gender));
|
||||||
|
}, [ figures ]);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
if(!isVisible || isInitalized) return;
|
if(!categories) return;
|
||||||
|
|
||||||
const newEditor = new AvatarEditor();
|
selectCategory(AvatarEditorFigureCategory.GENERIC);
|
||||||
|
}, [ categories, selectCategory ]);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
if(!figureData) return;
|
||||||
|
|
||||||
|
AvatarEditorUtilities.CURRENT_FIGURE = figureData;
|
||||||
|
|
||||||
|
resetCategories();
|
||||||
|
|
||||||
|
return () => AvatarEditorUtilities.CURRENT_FIGURE = null;
|
||||||
|
}, [ figureData, resetCategories ]);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
if(!isVisible) return;
|
||||||
|
|
||||||
|
if(!figures)
|
||||||
|
{
|
||||||
|
setupFigures();
|
||||||
|
|
||||||
setAvatarEditor(newEditor);
|
|
||||||
setIsInitalized(true);
|
setIsInitalized(true);
|
||||||
}, [ isVisible, isInitalized ]);
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}, [ isVisible, figures, setupFigures ]);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
if(!isVisible || !avatarEditor) return;
|
if(!isVisible || !isInitalized || !needsReset) return;
|
||||||
|
|
||||||
loadAvatarInEditor(GetSessionDataManager().figure, GetSessionDataManager().gender);
|
loadAvatarInEditor(GetSessionDataManager().figure, GetSessionDataManager().gender);
|
||||||
}, [ isVisible, avatarEditor, loadAvatarInEditor ]);
|
setNeedsReset(false);
|
||||||
|
}, [ isVisible, isInitalized, needsReset, loadAvatarInEditor ]);
|
||||||
|
|
||||||
|
if(!isVisible) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AvatarEditorContextProvider value={ { avatarEditorState, dispatchAvatarEditorState } }>
|
|
||||||
{ isVisible &&
|
|
||||||
<NitroCardView className="nitro-avatar-editor">
|
<NitroCardView className="nitro-avatar-editor">
|
||||||
<NitroCardHeaderView headerText={ LocalizeText('avatareditor.title') } onCloseClick={ event => setIsVisible(false) } />
|
<NitroCardHeaderView headerText={ LocalizeText('avatareditor.title') } onCloseClick={ event => setIsVisible(false) } />
|
||||||
<NitroCardTabsView>
|
<NitroCardTabsView>
|
||||||
{ categories && (categories.size > 0) && Array.from(categories.keys()).map(category =>
|
{ categories && (categories.size > 0) && activeCategory && Array.from(categories.keys()).map(category =>
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
<NitroCardTabsItemView key={ category } isActive={ (activeCategory.name === category) } onClick={ event => selectCategory(category) }>
|
<NitroCardTabsItemView key={ category } isActive={ (activeCategory.name === category) } onClick={ event => selectCategory(category) }>
|
||||||
@ -152,9 +210,35 @@ export const AvatarEditorView: FC<AvatarEditorViewProps> = props =>
|
|||||||
})}
|
})}
|
||||||
</NitroCardTabsView>
|
</NitroCardTabsView>
|
||||||
<NitroCardContentView>
|
<NitroCardContentView>
|
||||||
{ activeCategory && <AvatarEditorModelView model={ activeCategory } editor={ avatarEditor } selectGender={ selectGender } /> }
|
<div className="row h-100">
|
||||||
|
<div className="col-9 d-flex flex-column h-100">
|
||||||
|
{ activeCategory && <AvatarEditorModelView model={ activeCategory } gender={ figureData.gender } setGender={ setGender } /> }
|
||||||
|
</div>
|
||||||
|
<div className="col-3 d-flex flex-column h-100">
|
||||||
|
{ figureData &&
|
||||||
|
<div className="figure-preview-container">
|
||||||
|
<AvatarEditorFigurePreviewView figureData={ figureData } />
|
||||||
|
<div className="avatar-spotlight" />
|
||||||
|
<div className="avatar-shadow" />
|
||||||
|
<div className="arrow-container">
|
||||||
|
<i className="icon arrow-left-icon" onClick={ event => rotateFigure(figureData.direction + 1) } />
|
||||||
|
<i className="icon arrow-right-icon" onClick={ event => rotateFigure(figureData.direction - 1) } />
|
||||||
|
</div>
|
||||||
|
</div> }
|
||||||
|
<div className="d-flex flex-column mt-1">
|
||||||
|
<div className="btn-group mb-1">
|
||||||
|
<button type="button" className="btn btn-sm btn-secondary" onClick={ resetFigure }>
|
||||||
|
<i className="fas fa-undo" />
|
||||||
|
</button>
|
||||||
|
<button type="button" className="btn btn-sm btn-secondary" onClick={ clearFigure }>
|
||||||
|
<i className="fas fa-trash" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<button type="button" className="btn btn-success btn-sm w-100" onClick={ saveFigure }>{ LocalizeText('avatareditor.save') }</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</NitroCardContentView>
|
</NitroCardContentView>
|
||||||
</NitroCardView> }
|
</NitroCardView>
|
||||||
</AvatarEditorContextProvider>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,88 +1,79 @@
|
|||||||
import { IPalette, IPartColor, ISetType, IStructureData } from 'nitro-renderer';
|
import { IPartColor } from 'nitro-renderer';
|
||||||
import { GetAvatarRenderManager, GetConfiguration, GetSessionDataManager } from '../../../api';
|
import { GetAvatarPalette, GetAvatarRenderManager, GetAvatarSetType, GetClubMemberLevel, GetConfiguration } from '../../../api';
|
||||||
import { AvatarEditorGridColorItem } from './AvatarEditorGridColorItem';
|
import { AvatarEditorGridColorItem } from './AvatarEditorGridColorItem';
|
||||||
import { AvatarEditorGridPartItem } from './AvatarEditorGridPartItem';
|
import { AvatarEditorGridPartItem } from './AvatarEditorGridPartItem';
|
||||||
import { CategoryBaseModel } from './CategoryBaseModel';
|
import { CategoryBaseModel } from './CategoryBaseModel';
|
||||||
import { CategoryData } from './CategoryData';
|
import { CategoryData } from './CategoryData';
|
||||||
import { FigureData } from './FigureData';
|
import { FigureData } from './FigureData';
|
||||||
|
|
||||||
const MAX_PALETTES: number = 2;
|
export class AvatarEditorUtilities
|
||||||
const DEFAULT_MALE_FIGURE: string = 'hr-100.hd-180-7.ch-215-66.lg-270-79.sh-305-62.ha-1002-70.wa-2007';
|
|
||||||
const DEFAULT_FEMALE_FIGURE: string = 'hr-515-33.hd-600-1.ch-635-70.lg-716-66-62.sh-735-68';
|
|
||||||
|
|
||||||
export class AvatarEditor
|
|
||||||
{
|
{
|
||||||
private _figureStructureData: IStructureData = GetAvatarRenderManager().structureData;
|
private static MAX_PALETTES: number = 2;
|
||||||
private _figures: Map<string, FigureData> = new Map();
|
|
||||||
private _gender: string = FigureData.MALE;
|
|
||||||
private _notifier: () => void = null;
|
|
||||||
|
|
||||||
constructor()
|
public static CURRENT_FIGURE: FigureData = null;
|
||||||
|
|
||||||
|
public static getGender(gender: string): string
|
||||||
{
|
{
|
||||||
const maleFigure = new FigureData();
|
switch(gender)
|
||||||
const femaleFigure = new FigureData();
|
{
|
||||||
|
case FigureData.MALE:
|
||||||
maleFigure.loadAvatarData(DEFAULT_MALE_FIGURE, FigureData.MALE);
|
case 'm':
|
||||||
femaleFigure.loadAvatarData(DEFAULT_FEMALE_FIGURE, FigureData.FEMALE);
|
case 'M':
|
||||||
|
gender = FigureData.MALE;
|
||||||
this._figures.set(FigureData.MALE, maleFigure);
|
break;
|
||||||
this._figures.set(FigureData.FEMALE, femaleFigure);
|
case FigureData.FEMALE:
|
||||||
|
case 'f':
|
||||||
|
case 'F':
|
||||||
|
gender = FigureData.FEMALE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
gender = FigureData.MALE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSetType(setType: string): ISetType
|
return gender;
|
||||||
{
|
|
||||||
if(!this._figureStructureData) return null;
|
|
||||||
|
|
||||||
return this._figureStructureData.getSetType(setType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public getPalette(paletteId: number): IPalette
|
public static createCategory(model: CategoryBaseModel, name: string): CategoryData
|
||||||
{
|
{
|
||||||
if(!this._figureStructureData) return null;
|
if(!model || !name || !this.CURRENT_FIGURE) return null;
|
||||||
|
|
||||||
return this._figureStructureData.getPalette(paletteId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public createCategory(model: CategoryBaseModel, name: string): CategoryData
|
|
||||||
{
|
|
||||||
if(!model || !name) return null;
|
|
||||||
|
|
||||||
const partItems: AvatarEditorGridPartItem[] = [];
|
const partItems: AvatarEditorGridPartItem[] = [];
|
||||||
const colorItems: AvatarEditorGridColorItem[][] = [];
|
const colorItems: AvatarEditorGridColorItem[][] = [];
|
||||||
|
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
|
||||||
while(i < MAX_PALETTES)
|
while(i < this.MAX_PALETTES)
|
||||||
{
|
{
|
||||||
colorItems.push([]);
|
colorItems.push([]);
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
const setType = this.getSetType(name);
|
const setType = GetAvatarSetType(name);
|
||||||
|
|
||||||
if(!setType) return null;
|
if(!setType) return null;
|
||||||
|
|
||||||
const palette = this.getPalette(setType.paletteID);
|
const palette = GetAvatarPalette(setType.paletteID);
|
||||||
|
|
||||||
if(!palette) return null;
|
if(!palette) return null;
|
||||||
|
|
||||||
let colorIds = this.figureData.getColourIds(name);
|
let colorIds = this.CURRENT_FIGURE.getColorIds(name);
|
||||||
|
|
||||||
if(!colorIds) colorIds = [];
|
if(!colorIds) colorIds = [];
|
||||||
|
|
||||||
const partColors: IPartColor[] = new Array(colorIds.length);
|
const partColors: IPartColor[] = new Array(colorIds.length);
|
||||||
const clubItemsDimmed = this.clubItemsDimmed;
|
const clubItemsDimmed = this.clubItemsDimmed;
|
||||||
|
const clubMemberLevel = GetClubMemberLevel();
|
||||||
|
|
||||||
for(const partColor of palette.colors.values())
|
for(const partColor of palette.colors.values())
|
||||||
{
|
{
|
||||||
if(partColor.isSelectable && (clubItemsDimmed || (this.clubMemberLevel >= partColor.clubLevel)))
|
if(partColor.isSelectable && (clubItemsDimmed || (clubMemberLevel >= partColor.clubLevel)))
|
||||||
{
|
{
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
|
||||||
while(i < MAX_PALETTES)
|
while(i < this.MAX_PALETTES)
|
||||||
{
|
{
|
||||||
const isDisabled = (this.clubMemberLevel < partColor.clubLevel);
|
const isDisabled = (clubMemberLevel < partColor.clubLevel);
|
||||||
const colorItem = new AvatarEditorGridColorItem(partColor, isDisabled);
|
const colorItem = new AvatarEditorGridColorItem(partColor, isDisabled);
|
||||||
|
|
||||||
colorItems[i].push(colorItem);
|
colorItems[i].push(colorItem);
|
||||||
@ -108,11 +99,11 @@ export class AvatarEditor
|
|||||||
|
|
||||||
if(clubItemsDimmed)
|
if(clubItemsDimmed)
|
||||||
{
|
{
|
||||||
mandatorySetIds = GetAvatarRenderManager().getMandatoryAvatarPartSetIds(this._gender, 2);
|
mandatorySetIds = GetAvatarRenderManager().getMandatoryAvatarPartSetIds(this.CURRENT_FIGURE.gender, 2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mandatorySetIds = GetAvatarRenderManager().getMandatoryAvatarPartSetIds(this._gender, this.clubMemberLevel);
|
mandatorySetIds = GetAvatarRenderManager().getMandatoryAvatarPartSetIds(this.CURRENT_FIGURE.gender, clubMemberLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
const isntMandatorySet = (mandatorySetIds.indexOf(name) === -1);
|
const isntMandatorySet = (mandatorySetIds.indexOf(name) === -1);
|
||||||
@ -142,17 +133,15 @@ export class AvatarEditor
|
|||||||
{
|
{
|
||||||
isValidGender = true;
|
isValidGender = true;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
else if(partSet.gender === this.CURRENT_FIGURE.gender)
|
||||||
if(partSet.gender === this._gender)
|
|
||||||
{
|
{
|
||||||
isValidGender = true;
|
isValidGender = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if(partSet.isSelectable && isValidGender && (clubItemsDimmed || (this.clubMemberLevel >= partSet.clubLevel)))
|
if(partSet.isSelectable && isValidGender && (clubItemsDimmed || (clubMemberLevel >= partSet.clubLevel)))
|
||||||
{
|
{
|
||||||
const isDisabled = (this.clubMemberLevel < partSet.clubLevel);
|
const isDisabled = (clubMemberLevel < partSet.clubLevel);
|
||||||
|
|
||||||
let isValid = true;
|
let isValid = true;
|
||||||
|
|
||||||
@ -186,7 +175,7 @@ export class AvatarEditor
|
|||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
|
|
||||||
while(i < MAX_PALETTES)
|
while(i < this.MAX_PALETTES)
|
||||||
{
|
{
|
||||||
colorItems[i].sort(this.colorSorter);
|
colorItems[i].sort(this.colorSorter);
|
||||||
|
|
||||||
@ -196,7 +185,7 @@ export class AvatarEditor
|
|||||||
return new CategoryData(name, partItems, colorItems);
|
return new CategoryData(name, partItems, colorItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
private clubSorter(a: AvatarEditorGridPartItem, b: AvatarEditorGridPartItem): number
|
public static clubSorter(a: AvatarEditorGridPartItem, b: AvatarEditorGridPartItem): number
|
||||||
{
|
{
|
||||||
const clubLevelA = (!a.partSet ? 9999999999 : a.partSet.clubLevel);
|
const clubLevelA = (!a.partSet ? 9999999999 : a.partSet.clubLevel);
|
||||||
const clubLevelB = (!b.partSet ? 9999999999 : b.partSet.clubLevel);
|
const clubLevelB = (!b.partSet ? 9999999999 : b.partSet.clubLevel);
|
||||||
@ -218,7 +207,23 @@ export class AvatarEditor
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private noobSorter(a: AvatarEditorGridPartItem, b: AvatarEditorGridPartItem): number
|
public static colorSorter(a: AvatarEditorGridColorItem, b: AvatarEditorGridColorItem): number
|
||||||
|
{
|
||||||
|
const clubLevelA = (!a.partColor ? -1 : a.partColor.clubLevel);
|
||||||
|
const clubLevelB = (!b.partColor ? -1 : b.partColor.clubLevel);
|
||||||
|
|
||||||
|
if(clubLevelA < clubLevelB) return -1;
|
||||||
|
|
||||||
|
if(clubLevelA > clubLevelB) return 1;
|
||||||
|
|
||||||
|
if(a.partColor.index < b.partColor.index) return -1;
|
||||||
|
|
||||||
|
if(a.partColor.index > b.partColor.index) return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static noobSorter(a: AvatarEditorGridPartItem, b: AvatarEditorGridPartItem): number
|
||||||
{
|
{
|
||||||
const clubLevelA = (!a.partSet ? -1 : a.partSet.clubLevel);
|
const clubLevelA = (!a.partSet ? -1 : a.partSet.clubLevel);
|
||||||
const clubLevelB = (!b.partSet ? -1 : b.partSet.clubLevel);
|
const clubLevelB = (!b.partSet ? -1 : b.partSet.clubLevel);
|
||||||
@ -240,67 +245,33 @@ export class AvatarEditor
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private colorSorter(a: AvatarEditorGridColorItem, b: AvatarEditorGridColorItem): number
|
public static avatarSetFirstSelectableColor(name: string): number
|
||||||
{
|
{
|
||||||
const clubLevelA = (!a.partColor ? -1 : a.partColor.clubLevel);
|
const setType = GetAvatarSetType(name);
|
||||||
const clubLevelB = (!b.partColor ? -1 : b.partColor.clubLevel);
|
|
||||||
|
|
||||||
if(clubLevelA < clubLevelB) return -1;
|
if(!setType) return -1;
|
||||||
|
|
||||||
if(clubLevelA > clubLevelB) return 1;
|
const palette = GetAvatarPalette(setType.paletteID);
|
||||||
|
|
||||||
if(a.partColor.index < b.partColor.index) return -1;
|
if(!palette) return -1;
|
||||||
|
|
||||||
if(a.partColor.index > b.partColor.index) return 1;
|
for(const color of palette.colors.values())
|
||||||
|
{
|
||||||
|
if(!color.isSelectable || (GetClubMemberLevel() < color.clubLevel)) continue;
|
||||||
|
|
||||||
return 0;
|
return color.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get clubMemberLevel(): number
|
return -1;
|
||||||
{
|
|
||||||
return GetSessionDataManager().clubLevel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private get clubItemsFirst(): boolean
|
public static get clubItemsFirst(): boolean
|
||||||
{
|
{
|
||||||
return GetConfiguration<boolean>('avatareditor.show.clubitems.first', true);
|
return GetConfiguration<boolean>('avatareditor.show.clubitems.first', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private get clubItemsDimmed(): boolean
|
public static get clubItemsDimmed(): boolean
|
||||||
{
|
{
|
||||||
return GetConfiguration<boolean>('avatareditor.show.clubitems.dimmed', true);
|
return GetConfiguration<boolean>('avatareditor.show.clubitems.dimmed', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public get figureData(): FigureData
|
|
||||||
{
|
|
||||||
return this._figures.get(this._gender);
|
|
||||||
}
|
|
||||||
|
|
||||||
public get gender(): string
|
|
||||||
{
|
|
||||||
return this._gender;
|
|
||||||
}
|
|
||||||
|
|
||||||
public set gender(gender: string)
|
|
||||||
{
|
|
||||||
if(this._gender === gender) return;
|
|
||||||
|
|
||||||
this._gender = gender;
|
|
||||||
|
|
||||||
if(this.figureData) this.figureData.notify = this.notify;
|
|
||||||
|
|
||||||
if(this.notify) this.notify();
|
|
||||||
}
|
|
||||||
|
|
||||||
public get notify(): () => void
|
|
||||||
{
|
|
||||||
return this._notifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
public set notify(notifier: () => void)
|
|
||||||
{
|
|
||||||
if(this.figureData) this.figureData.notify = notifier;
|
|
||||||
|
|
||||||
this._notifier = notifier;
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
import { AvatarEditorFigureCategory, AvatarScaleType, AvatarSetType, IAvatarImageListener } from 'nitro-renderer';
|
import { AvatarEditorFigureCategory, AvatarScaleType, AvatarSetType, IAvatarImageListener } from 'nitro-renderer';
|
||||||
import { GetAvatarRenderManager } from '../../../api';
|
import { GetAvatarRenderManager } from '../../../api';
|
||||||
|
import { AvatarEditorUtilities } from './AvatarEditorUtilities';
|
||||||
import { CategoryBaseModel } from './CategoryBaseModel';
|
import { CategoryBaseModel } from './CategoryBaseModel';
|
||||||
import { FigureData } from './FigureData';
|
import { FigureData } from './FigureData';
|
||||||
|
|
||||||
@ -25,15 +26,15 @@ export class BodyModel extends CategoryBaseModel implements IAvatarImageListener
|
|||||||
|
|
||||||
protected updateSelectionsFromFigure(name: string): void
|
protected updateSelectionsFromFigure(name: string): void
|
||||||
{
|
{
|
||||||
if(!this._categories || !this._editor || !this._editor.figureData) return;
|
if(!this._categories || !AvatarEditorUtilities.CURRENT_FIGURE) return;
|
||||||
|
|
||||||
const category = this._categories.get(name);
|
const category = this._categories.get(name);
|
||||||
|
|
||||||
if(!category) return;
|
if(!category) return;
|
||||||
|
|
||||||
const setId = this._editor.figureData.getPartSetId(name);
|
const setId = AvatarEditorUtilities.CURRENT_FIGURE.getPartSetId(name);
|
||||||
|
|
||||||
let colorIds = this._editor.figureData.getColourIds(name);
|
let colorIds = AvatarEditorUtilities.CURRENT_FIGURE.getColorIds(name);
|
||||||
|
|
||||||
if(!colorIds) colorIds = [];
|
if(!colorIds) colorIds = [];
|
||||||
|
|
||||||
@ -42,7 +43,7 @@ export class BodyModel extends CategoryBaseModel implements IAvatarImageListener
|
|||||||
|
|
||||||
for(const part of category.parts)
|
for(const part of category.parts)
|
||||||
{
|
{
|
||||||
const figure = this._editor.figureData.getFigureStringWithFace(part.id);
|
const figure = AvatarEditorUtilities.CURRENT_FIGURE.getFigureStringWithFace(part.id);
|
||||||
const avatarImage = GetAvatarRenderManager().createAvatarImage(figure, AvatarScaleType.LARGE, null, this);
|
const avatarImage = GetAvatarRenderManager().createAvatarImage(figure, AvatarScaleType.LARGE, null, this);
|
||||||
|
|
||||||
const sprite = avatarImage.getImageAsSprite(AvatarSetType.HEAD);
|
const sprite = avatarImage.getImageAsSprite(AvatarSetType.HEAD);
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
import { AvatarEditor } from './AvatarEditor';
|
import { AvatarEditorUtilities } from './AvatarEditorUtilities';
|
||||||
import { CategoryData } from './CategoryData';
|
import { CategoryData } from './CategoryData';
|
||||||
import { IAvatarEditorCategoryModel } from './IAvatarEditorCategoryModel';
|
import { IAvatarEditorCategoryModel } from './IAvatarEditorCategoryModel';
|
||||||
|
|
||||||
export class CategoryBaseModel implements IAvatarEditorCategoryModel
|
export class CategoryBaseModel implements IAvatarEditorCategoryModel
|
||||||
{
|
{
|
||||||
protected _editor: AvatarEditor;
|
|
||||||
protected _categories: Map<string, CategoryData>;
|
protected _categories: Map<string, CategoryData>;
|
||||||
protected _isInitalized: boolean;
|
protected _isInitalized: boolean;
|
||||||
protected _maxPaletteCount: number;
|
protected _maxPaletteCount: number;
|
||||||
private _disposed: boolean;
|
private _disposed: boolean;
|
||||||
|
|
||||||
constructor(editor: AvatarEditor)
|
constructor()
|
||||||
{
|
{
|
||||||
this._editor = editor;
|
|
||||||
this._isInitalized = false;
|
this._isInitalized = false;
|
||||||
this._maxPaletteCount = 0;
|
this._maxPaletteCount = 0;
|
||||||
}
|
}
|
||||||
@ -51,7 +49,7 @@ export class CategoryBaseModel implements IAvatarEditorCategoryModel
|
|||||||
|
|
||||||
if(existing) return;
|
if(existing) return;
|
||||||
|
|
||||||
existing = this._editor.createCategory(this, name);
|
existing = AvatarEditorUtilities.createCategory(this, name);
|
||||||
|
|
||||||
if(!existing) return;
|
if(!existing) return;
|
||||||
|
|
||||||
@ -66,9 +64,9 @@ export class CategoryBaseModel implements IAvatarEditorCategoryModel
|
|||||||
|
|
||||||
if(!category) return;
|
if(!category) return;
|
||||||
|
|
||||||
const setId = this._editor.figureData.getPartSetId(figure);
|
const setId = AvatarEditorUtilities.CURRENT_FIGURE.getPartSetId(figure);
|
||||||
|
|
||||||
let colorIds = this._editor.figureData.getColourIds(figure);
|
let colorIds = AvatarEditorUtilities.CURRENT_FIGURE.getColorIds(figure);
|
||||||
|
|
||||||
if(!colorIds) colorIds = [];
|
if(!colorIds) colorIds = [];
|
||||||
|
|
||||||
@ -120,9 +118,9 @@ export class CategoryBaseModel implements IAvatarEditorCategoryModel
|
|||||||
{
|
{
|
||||||
const partItem = category.getCurrentPart();
|
const partItem = category.getCurrentPart();
|
||||||
|
|
||||||
if(partItem && this._editor && this._editor.figureData)
|
if(partItem && AvatarEditorUtilities.CURRENT_FIGURE)
|
||||||
{
|
{
|
||||||
this._editor.figureData.savePartData(name, partItem.id, category.getSelectedColorIds(), true);
|
AvatarEditorUtilities.CURRENT_FIGURE.savePartData(name, partItem.id, category.getSelectedColorIds(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
didStrip = true;
|
didStrip = true;
|
||||||
@ -148,9 +146,9 @@ export class CategoryBaseModel implements IAvatarEditorCategoryModel
|
|||||||
{
|
{
|
||||||
const partItem = category.getCurrentPart();
|
const partItem = category.getCurrentPart();
|
||||||
|
|
||||||
if(partItem && this._editor && this._editor.figureData)
|
if(partItem && AvatarEditorUtilities.CURRENT_FIGURE)
|
||||||
{
|
{
|
||||||
this._editor.figureData.savePartData(name, partItem.id, category.getSelectedColorIds(), true);
|
AvatarEditorUtilities.CURRENT_FIGURE.savePartData(name, partItem.id, category.getSelectedColorIds(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
didStrip = true;
|
didStrip = true;
|
||||||
@ -185,7 +183,7 @@ export class CategoryBaseModel implements IAvatarEditorCategoryModel
|
|||||||
|
|
||||||
this._maxPaletteCount = partItem.maxColorIndex;
|
this._maxPaletteCount = partItem.maxColorIndex;
|
||||||
|
|
||||||
this._editor.figureData.savePartData(category, partItem.id, categoryData.getSelectedColorIds(), true);
|
AvatarEditorUtilities.CURRENT_FIGURE.savePartData(category, partItem.id, categoryData.getSelectedColorIds(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public selectColor(category: string, colorIndex: number, paletteId: number): void
|
public selectColor(category: string, colorIndex: number, paletteId: number): void
|
||||||
@ -209,7 +207,7 @@ export class CategoryBaseModel implements IAvatarEditorCategoryModel
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._editor.figureData.savePartSetColourId(category, categoryData.getSelectedColorIds(), true);
|
AvatarEditorUtilities.CURRENT_FIGURE.savePartSetColourId(category, categoryData.getSelectedColorIds(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCategoryData(category: string): CategoryData
|
public getCategoryData(category: string): CategoryData
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
export class FigureData
|
import { AvatarEditorUtilities } from './AvatarEditorUtilities';
|
||||||
|
|
||||||
|
export class FigureData
|
||||||
{
|
{
|
||||||
|
private static DEFAULT_DIRECTION: number = 4;
|
||||||
|
|
||||||
public static MALE: string = 'M';
|
public static MALE: string = 'M';
|
||||||
public static FEMALE: string = 'F';
|
public static FEMALE: string = 'F';
|
||||||
public static UNISEX: string = 'U';
|
public static UNISEX: string = 'U';
|
||||||
@ -24,6 +28,7 @@
|
|||||||
private _data: Map<string, number>;
|
private _data: Map<string, number>;
|
||||||
private _colors: Map<string, number[]>;
|
private _colors: Map<string, number[]>;
|
||||||
private _gender: string = 'M';
|
private _gender: string = 'M';
|
||||||
|
private _direction: number = FigureData.DEFAULT_DIRECTION;
|
||||||
private _avatarEffectType: number = -1;
|
private _avatarEffectType: number = -1;
|
||||||
private _notifier: () => void = null;
|
private _notifier: () => void = null;
|
||||||
|
|
||||||
@ -80,14 +85,13 @@
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getColourIds(colorId: string): number[]
|
public getColorIds(setType: string): number[]
|
||||||
{
|
{
|
||||||
const existing = this._colors.get(colorId);
|
const existing = this._colors.get(setType);
|
||||||
|
|
||||||
if(existing !== undefined) return existing;
|
if(existing !== undefined) return existing;
|
||||||
|
|
||||||
return [];
|
return [ AvatarEditorUtilities.avatarSetFirstSelectableColor(setType) ];
|
||||||
// return [this._avatarEditor._Str_24919(k)];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public getFigureString(): string
|
public getFigureString(): string
|
||||||
@ -167,9 +171,9 @@
|
|||||||
if(_arg_3) this.updateView();
|
if(_arg_3) this.updateView();
|
||||||
}
|
}
|
||||||
|
|
||||||
public savePartSetColourId(k: string, _arg_2: number[], _arg_3: boolean = true): void
|
public savePartSetColourId(setType: string, colorIds: number[], update: boolean = true): void
|
||||||
{
|
{
|
||||||
switch(k)
|
switch(setType)
|
||||||
{
|
{
|
||||||
case FigureData.FACE:
|
case FigureData.FACE:
|
||||||
case FigureData.HAIR:
|
case FigureData.HAIR:
|
||||||
@ -184,11 +188,11 @@
|
|||||||
case FigureData.TROUSERS:
|
case FigureData.TROUSERS:
|
||||||
case FigureData.SHOES:
|
case FigureData.SHOES:
|
||||||
case FigureData.TROUSER_ACCESSORIES:
|
case FigureData.TROUSER_ACCESSORIES:
|
||||||
this._colors.set(k, _arg_2);
|
this._colors.set(setType, colorIds);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_arg_3) this.updateView();
|
if(update) this.updateView();
|
||||||
}
|
}
|
||||||
|
|
||||||
public getFigureStringWithFace(k: number, override = true): string
|
public getFigureStringWithFace(k: number, override = true): string
|
||||||
@ -249,6 +253,18 @@
|
|||||||
return this._gender;
|
return this._gender;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get direction(): number
|
||||||
|
{
|
||||||
|
return this._direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set direction(direction: number)
|
||||||
|
{
|
||||||
|
this._direction = direction;
|
||||||
|
|
||||||
|
this.updateView();
|
||||||
|
}
|
||||||
|
|
||||||
public set avatarEffectType(k: number)
|
public set avatarEffectType(k: number)
|
||||||
{
|
{
|
||||||
this._avatarEffectType = k;
|
this._avatarEffectType = k;
|
||||||
|
@ -4,7 +4,7 @@ import { AvatarEditorFigurePreviewViewProps } from './AvatarEditorFigurePreviewV
|
|||||||
|
|
||||||
export const AvatarEditorFigurePreviewView: FC<AvatarEditorFigurePreviewViewProps> = props =>
|
export const AvatarEditorFigurePreviewView: FC<AvatarEditorFigurePreviewViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { editor = null } = props;
|
const { figureData = null } = props;
|
||||||
const [ updateId, setUpdateId ] = useState(-1);
|
const [ updateId, setUpdateId ] = useState(-1);
|
||||||
|
|
||||||
const rerender = useCallback(() =>
|
const rerender = useCallback(() =>
|
||||||
@ -14,15 +14,15 @@ export const AvatarEditorFigurePreviewView: FC<AvatarEditorFigurePreviewViewProp
|
|||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
if(!editor) return;
|
if(!figureData) return;
|
||||||
|
|
||||||
editor.notify = rerender;
|
figureData.notify = rerender;
|
||||||
|
|
||||||
return () =>
|
return () =>
|
||||||
{
|
{
|
||||||
editor.notify = null;
|
figureData.notify = null;
|
||||||
}
|
}
|
||||||
}, [ editor, rerender ] );
|
}, [ figureData, rerender ] );
|
||||||
|
|
||||||
return <AvatarImageView figure={ editor.figureData.getFigureString() } direction={ 4 } scale={ 2 } />
|
return <AvatarImageView figure={ figureData.getFigureString() } direction={ figureData.direction } scale={ 2 } />
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { AvatarEditor } from '../../common/AvatarEditor';
|
import { FigureData } from '../../common/FigureData';
|
||||||
|
|
||||||
export interface AvatarEditorFigurePreviewViewProps
|
export interface AvatarEditorFigurePreviewViewProps
|
||||||
{
|
{
|
||||||
editor: AvatarEditor;
|
figureData: FigureData;
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,9 @@ export const AvatarEditorFigureSetItemView: FC<AvatarEditorFigureSetItemViewProp
|
|||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NitroCardGridItemView itemImage={ partItem.imageUrl } itemActive={ partItem.isSelected } onClick={ () => onClick(partItem) }>
|
<NitroCardGridItemView itemImage={ (partItem.isClear ? undefined : partItem.imageUrl) } itemActive={ partItem.isSelected } onClick={ () => onClick(partItem) }>
|
||||||
{ partItem.isHC && <CurrencyIcon type={ 'hc' } /> }
|
{ partItem.isHC && <CurrencyIcon type={ 'hc' } /> }
|
||||||
|
{ partItem.isClear && <i className="icon clear-icon" /> }
|
||||||
</NitroCardGridItemView>
|
</NitroCardGridItemView>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,13 @@
|
|||||||
import { UserFigureComposer } from 'nitro-renderer';
|
|
||||||
import { FC, useCallback, useEffect, useState } from 'react';
|
import { FC, useCallback, useEffect, useState } from 'react';
|
||||||
import { SendMessageHook } from '../../../../hooks';
|
|
||||||
import { LocalizeText } from '../../../../utils/LocalizeText';
|
|
||||||
import { CategoryData } from '../../common/CategoryData';
|
import { CategoryData } from '../../common/CategoryData';
|
||||||
import { FigureData } from '../../common/FigureData';
|
import { FigureData } from '../../common/FigureData';
|
||||||
import { AvatarEditorFigurePreviewView } from '../figure-preview/AvatarEditorFigurePreviewView';
|
|
||||||
import { AvatarEditorFigureSetView } from '../figure-set/AvatarEditorFigureSetView';
|
import { AvatarEditorFigureSetView } from '../figure-set/AvatarEditorFigureSetView';
|
||||||
import { AvatarEditorPaletteSetView } from '../palette-set/AvatarEditorPaletteSetView';
|
import { AvatarEditorPaletteSetView } from '../palette-set/AvatarEditorPaletteSetView';
|
||||||
import { AvatarEditorModelViewProps } from './AvatarEditorModelView.types';
|
import { AvatarEditorModelViewProps } from './AvatarEditorModelView.types';
|
||||||
|
|
||||||
export const AvatarEditorModelView: FC<AvatarEditorModelViewProps> = props =>
|
export const AvatarEditorModelView: FC<AvatarEditorModelViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { model = null, editor = null, selectGender = null } = props;
|
const { model = null, gender = null, setGender = null } = props;
|
||||||
const [ activeCategory, setActiveCategory ] = useState<CategoryData>(null);
|
const [ activeCategory, setActiveCategory ] = useState<CategoryData>(null);
|
||||||
const [ maxPaletteCount, setMaxPaletteCount ] = useState(1);
|
const [ maxPaletteCount, setMaxPaletteCount ] = useState(1);
|
||||||
|
|
||||||
@ -35,13 +31,6 @@ export const AvatarEditorModelView: FC<AvatarEditorModelViewProps> = props =>
|
|||||||
}
|
}
|
||||||
}, [ model ]);
|
}, [ model ]);
|
||||||
|
|
||||||
const saveFigure = useCallback(() =>
|
|
||||||
{
|
|
||||||
const figureData = editor.figureData;
|
|
||||||
|
|
||||||
SendMessageHook(new UserFigureComposer(figureData.gender, figureData.getFigureString()));
|
|
||||||
}, [ editor ]);
|
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
model.init();
|
model.init();
|
||||||
@ -58,49 +47,35 @@ export const AvatarEditorModelView: FC<AvatarEditorModelViewProps> = props =>
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="row h-100">
|
<div className="row h-100">
|
||||||
<div className="col-1 d-flex flex-column align-items-center h-100 pe-0">
|
<div className="col-2 d-flex flex-column align-items-center h-100">
|
||||||
{ model.canSetGender &&
|
{ model.canSetGender &&
|
||||||
<>
|
<>
|
||||||
<i className={ `icon male-icon ${ (editor.gender === FigureData.MALE) ? ' selected' : ''}` } onClick={ event => selectGender(FigureData.MALE) } />
|
<div className="d-flex justify-content-center align-items-center category-item cursor-pointer" onClick={ event => setGender(FigureData.MALE) }>
|
||||||
<i className={ `icon female-icon ${ (editor.gender === FigureData.FEMALE) ? ' selected' : ''}` } onClick={ event => selectGender(FigureData.FEMALE) } />
|
<i className={ `icon male-icon ${ (gender === FigureData.MALE) ? ' selected' : ''}` } />
|
||||||
|
</div>
|
||||||
|
<div className="d-flex justify-content-center align-items-center category-item cursor-pointer" onClick={ event => setGender(FigureData.FEMALE) }>
|
||||||
|
<i className={ `icon female-icon ${ (gender === FigureData.FEMALE) ? ' selected' : ''}` } />
|
||||||
|
</div>
|
||||||
</> }
|
</> }
|
||||||
{ !model.canSetGender && model.categories && (model.categories.size > 0) && Array.from(model.categories.keys()).map(name =>
|
{ !model.canSetGender && model.categories && (model.categories.size > 0) && Array.from(model.categories.keys()).map(name =>
|
||||||
{
|
{
|
||||||
const category = model.categories.get(name);
|
const category = model.categories.get(name);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<i className={ `icon ${ category.name }-icon mb-2 ${ (activeCategory === category) ? ' selected' : ''}` } onClick={ event => selectCategory(name) } />
|
<div key={ name } className="d-flex justify-content-center align-items-center category-item cursor-pointer" onClick={ event => selectCategory(name) }>
|
||||||
|
<i className={ `icon ${ category.name }-icon ${ (activeCategory === category) ? ' selected' : ''}` } />
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
<div className="col-4 d-flex flex-column h-100">
|
<div className="col-5 d-flex flex-column h-100">
|
||||||
<AvatarEditorFigureSetView model={ model } category={ activeCategory } setMaxPaletteCount={ setMaxPaletteCount } />
|
<AvatarEditorFigureSetView model={ model } category={ activeCategory } setMaxPaletteCount={ setMaxPaletteCount } />
|
||||||
</div>
|
</div>
|
||||||
<div className="col-3 d-flex flex-column h-100">
|
<div className="col-5 d-flex flex-column h-100">
|
||||||
<div className="figure-preview-container mb-2">
|
|
||||||
<AvatarEditorFigurePreviewView editor={ editor } />
|
|
||||||
<div className="arrow-container">
|
|
||||||
<i className="icon arrow-left-icon" />
|
|
||||||
<i className="icon arrow-right-icon" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="d-flex flex-column">
|
|
||||||
<div className="btn-group mb-1">
|
|
||||||
<button type="button" className="btn btn-sm btn-secondary">
|
|
||||||
<i className="fas fa-undo" />
|
|
||||||
</button>
|
|
||||||
<button type="button" className="btn btn-sm btn-secondary">
|
|
||||||
<i className="fas fa-trash" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<button type="button" className="btn btn-success btn-sm w-100" onClick={ saveFigure }>{ LocalizeText('avatareditor.save') }</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="col-4 d-flex flex-column h-100">
|
|
||||||
{ (maxPaletteCount >= 1) &&
|
{ (maxPaletteCount >= 1) &&
|
||||||
<AvatarEditorPaletteSetView model={ model } category={ activeCategory } paletteSet={ activeCategory.getPalette(0) } paletteIndex={ 0 } /> }
|
<AvatarEditorPaletteSetView model={ model } category={ activeCategory } paletteSet={ activeCategory.getPalette(0) } paletteIndex={ 0 } /> }
|
||||||
{ (maxPaletteCount === 2) &&
|
{ (maxPaletteCount === 2) &&
|
||||||
<AvatarEditorPaletteSetView model={ model } category={ activeCategory } paletteSet={ activeCategory.getPalette(1) } paletteIndex={ 1 } /> }
|
<AvatarEditorPaletteSetView model={ model } category={ activeCategory } paletteSet={ activeCategory.getPalette(1) } paletteIndex={ 1 } className="mt-1" /> }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { AvatarEditor } from '../../common/AvatarEditor';
|
import { Dispatch, SetStateAction } from 'react';
|
||||||
import { IAvatarEditorCategoryModel } from '../../common/IAvatarEditorCategoryModel';
|
import { IAvatarEditorCategoryModel } from '../../common/IAvatarEditorCategoryModel';
|
||||||
|
|
||||||
export interface AvatarEditorModelViewProps
|
export interface AvatarEditorModelViewProps
|
||||||
{
|
{
|
||||||
model: IAvatarEditorCategoryModel;
|
model: IAvatarEditorCategoryModel;
|
||||||
editor: AvatarEditor;
|
gender: string;
|
||||||
selectGender: (gender: string) => void;
|
setGender: Dispatch<SetStateAction<string>>;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import { AvatarEditorPaletteSetItemProps } from './AvatarEditorPaletteSetItem.ty
|
|||||||
|
|
||||||
export const AvatarEditorPaletteSetItem: FC<AvatarEditorPaletteSetItemProps> = props =>
|
export const AvatarEditorPaletteSetItem: FC<AvatarEditorPaletteSetItemProps> = props =>
|
||||||
{
|
{
|
||||||
const { colorItem = null, onClick = null } = props;
|
const { colorItem = null, ...rest } = props;
|
||||||
const [ updateId, setUpdateId ] = useState(-1);
|
const [ updateId, setUpdateId ] = useState(-1);
|
||||||
|
|
||||||
const rerender = useCallback(() =>
|
const rerender = useCallback(() =>
|
||||||
@ -22,5 +22,5 @@ export const AvatarEditorPaletteSetItem: FC<AvatarEditorPaletteSetItemProps> = p
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return <NitroCardGridItemView itemColor={ colorItem.color } itemActive={ colorItem.isSelected } onClick={ () => onClick(colorItem) } />
|
return <NitroCardGridItemView itemColor={ colorItem.color } itemActive={ colorItem.isSelected } { ...rest } />
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
import { DetailsHTMLAttributes } from 'react';
|
||||||
import { AvatarEditorGridColorItem } from '../../common/AvatarEditorGridColorItem';
|
import { AvatarEditorGridColorItem } from '../../common/AvatarEditorGridColorItem';
|
||||||
|
|
||||||
export interface AvatarEditorPaletteSetItemProps
|
export interface AvatarEditorPaletteSetItemProps extends DetailsHTMLAttributes<HTMLDivElement>
|
||||||
{
|
{
|
||||||
colorItem: AvatarEditorGridColorItem;
|
colorItem: AvatarEditorGridColorItem;
|
||||||
onClick: (item: AvatarEditorGridColorItem) => void;
|
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import { AvatarEditorPaletteSetViewProps } from './AvatarEditorPaletteSetView.ty
|
|||||||
|
|
||||||
export const AvatarEditorPaletteSetView: FC<AvatarEditorPaletteSetViewProps> = props =>
|
export const AvatarEditorPaletteSetView: FC<AvatarEditorPaletteSetViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { model = null, category = null, paletteSet = [], paletteIndex = -1 } = props;
|
const { model = null, category = null, paletteSet = [], paletteIndex = -1, ...rest } = props;
|
||||||
|
|
||||||
const selectColor = useCallback((item: AvatarEditorGridColorItem) =>
|
const selectColor = useCallback((item: AvatarEditorGridColorItem) =>
|
||||||
{
|
{
|
||||||
@ -19,10 +19,10 @@ export const AvatarEditorPaletteSetView: FC<AvatarEditorPaletteSetViewProps> = p
|
|||||||
}, [ model, category, paletteSet, paletteIndex ]);
|
}, [ model, category, paletteSet, paletteIndex ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NitroCardGridView columns={ 3 } theme={ NitroCardGridThemes.THEME_SHADOWED }>
|
<NitroCardGridView columns={ 4 } theme={ NitroCardGridThemes.THEME_SHADOWED } { ...rest }>
|
||||||
{ (paletteSet.length > 0) && paletteSet.map((item, index) =>
|
{ (paletteSet.length > 0) && paletteSet.map((item, index) =>
|
||||||
{
|
{
|
||||||
return <AvatarEditorPaletteSetItem key={ index } colorItem={ item } onClick={ selectColor } />;
|
return <AvatarEditorPaletteSetItem key={ index } colorItem={ item } onClick={ event => selectColor(item) } />;
|
||||||
}) }
|
}) }
|
||||||
</NitroCardGridView>
|
</NitroCardGridView>
|
||||||
);
|
);
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
|
import { DetailsHTMLAttributes } from 'react';
|
||||||
import { AvatarEditorGridColorItem } from '../../common/AvatarEditorGridColorItem';
|
import { AvatarEditorGridColorItem } from '../../common/AvatarEditorGridColorItem';
|
||||||
import { CategoryData } from '../../common/CategoryData';
|
import { CategoryData } from '../../common/CategoryData';
|
||||||
import { IAvatarEditorCategoryModel } from '../../common/IAvatarEditorCategoryModel';
|
import { IAvatarEditorCategoryModel } from '../../common/IAvatarEditorCategoryModel';
|
||||||
|
|
||||||
export interface AvatarEditorPaletteSetViewProps
|
export interface AvatarEditorPaletteSetViewProps extends DetailsHTMLAttributes<HTMLDivElement>
|
||||||
{
|
{
|
||||||
model: IAvatarEditorCategoryModel;
|
model: IAvatarEditorCategoryModel;
|
||||||
category: CategoryData;
|
category: CategoryData;
|
||||||
|