Merge branch 'dev' into feature/youtube-tv
@ -3,12 +3,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1" />
|
||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000" />
|
||||||
<meta
|
|
||||||
name="description"
|
|
||||||
content="Web site created using create-react-app"
|
|
||||||
/>
|
|
||||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||||
<title>Nitro</title>
|
<title>Nitro</title>
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
"camera.url": "https://nitro.nitrots.co/camera",
|
"camera.url": "https://nitro.nitrots.co/camera",
|
||||||
"thumbnails.url": "https://nitro.nitrots.co/camera/thumbnail/%thumbnail%.png",
|
"thumbnails.url": "https://nitro.nitrots.co/camera/thumbnail/%thumbnail%.png",
|
||||||
"url.prefix": "http://localhost:3000",
|
"url.prefix": "http://localhost:3000",
|
||||||
|
"floorplan.tile.url": "${asset.url}/floorplan-editor/tiles.json",
|
||||||
"chat.viewer.height.percentage": 0.40,
|
"chat.viewer.height.percentage": 0.40,
|
||||||
"widget.dimmer.colorwheel": false,
|
"widget.dimmer.colorwheel": false,
|
||||||
"hotelview": {
|
"hotelview": {
|
||||||
|
18
src/App.scss
@ -17,13 +17,13 @@ $grid-active-border-color: $white;
|
|||||||
|
|
||||||
$toolbar-height: 55px;
|
$toolbar-height: 55px;
|
||||||
|
|
||||||
$achievement-width: 650px;
|
$achievement-width: 350px;
|
||||||
$achievement-height: 400px;
|
$achievement-height: 370px;
|
||||||
|
|
||||||
$avatar-editor-width: 620px;
|
$avatar-editor-width: 620px;
|
||||||
$avatar-editor-height: 374px;
|
$avatar-editor-height: 374px;
|
||||||
|
|
||||||
$catalog-width: 620px;
|
$catalog-width: 630px;
|
||||||
$catalog-height: 400px;
|
$catalog-height: 400px;
|
||||||
|
|
||||||
$inventory-width: 528px;
|
$inventory-width: 528px;
|
||||||
@ -32,6 +32,18 @@ $inventory-height: 320px;
|
|||||||
$navigator-width: 400px;
|
$navigator-width: 400px;
|
||||||
$navigator-height: 420px;
|
$navigator-height: 420px;
|
||||||
|
|
||||||
|
$chat-input-style-selector-widget-width: 200px;
|
||||||
|
$chat-input-style-selector-widget-height: 200px;
|
||||||
|
|
||||||
|
$user-profile-width: 560px;
|
||||||
|
$user-profile-height: 500px;
|
||||||
|
|
||||||
|
$nitro-widget-custom-stack-height-width: 275px;
|
||||||
|
$nitro-widget-custom-stack-height-height: 220px;
|
||||||
|
|
||||||
|
$nitro-widget-exchange-credit-width: 375px;
|
||||||
|
$nitro-widget-exchange-credit-height: 150px;
|
||||||
|
|
||||||
.nitro-app {
|
.nitro-app {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -11,9 +11,9 @@ import { MainView } from './views/main/MainView';
|
|||||||
|
|
||||||
export const App: FC<{}> = props =>
|
export const App: FC<{}> = props =>
|
||||||
{
|
{
|
||||||
const [ isReady, setIsReady ] = useState(false);
|
const [ isReady, setIsReady ] = useState(false);
|
||||||
const [ isError, setIsError ] = useState(false);
|
const [ isError, setIsError ] = useState(false);
|
||||||
const [ message, setMessage ] = useState('Getting Ready');
|
const [ message, setMessage ] = useState('Getting Ready');
|
||||||
|
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
if(!NitroConfig) throw new Error('NitroConfig is not defined!');
|
if(!NitroConfig) throw new Error('NitroConfig is not defined!');
|
||||||
@ -128,7 +128,7 @@ export const App: FC<{}> = props =>
|
|||||||
<div className="nitro-app overflow-hidden">
|
<div className="nitro-app overflow-hidden">
|
||||||
<div id="nitro-alerts-container" />
|
<div id="nitro-alerts-container" />
|
||||||
{ (!isReady || isError) && <LoadingView isError={ isError } message={ message } /> }
|
{ (!isReady || isError) && <LoadingView isError={ isError } message={ message } /> }
|
||||||
<TransitionAnimation type={ TransitionAnimationTypes.FADE_IN } inProp={ (isReady && !isError) } timeout={ 300 }>
|
<TransitionAnimation type={ TransitionAnimationTypes.FADE_IN } inProp={ (isReady && !isError) }>
|
||||||
<MainView />
|
<MainView />
|
||||||
</TransitionAnimation>
|
</TransitionAnimation>
|
||||||
</div>
|
</div>
|
||||||
|
@ -36,7 +36,7 @@ export class RoomWidgetUpdateDimmerEvent extends RoomWidgetUpdateEvent
|
|||||||
this._selectedPresetId = k;
|
this._selectedPresetId = k;
|
||||||
}
|
}
|
||||||
|
|
||||||
public setPresetValues(id: number, type: number, color: number, brightness: number):void
|
public setPresetValues(id: number, type: number, color: number, brightness: number): void
|
||||||
{
|
{
|
||||||
const preset = new RoomDimmerPreset(id, type, color, brightness);
|
const preset = new RoomDimmerPreset(id, type, color, brightness);
|
||||||
|
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
import { RoomWidgetUpdateEvent } from './RoomWidgetUpdateEvent';
|
||||||
|
|
||||||
|
export class RoomWidgetUpdateMannequinEvent extends RoomWidgetUpdateEvent
|
||||||
|
{
|
||||||
|
public static MANNEQUIN_UPDATE: string = 'RWUME_MANNEQUIN_UPDATE';
|
||||||
|
|
||||||
|
private _objectId: number;
|
||||||
|
private _figure: string;
|
||||||
|
private _gender: string;
|
||||||
|
private _name: string;
|
||||||
|
|
||||||
|
constructor(type: string, objectId: number, figure: string, gender: string, name: string)
|
||||||
|
{
|
||||||
|
super(type);
|
||||||
|
|
||||||
|
this._objectId = objectId;
|
||||||
|
this._figure = figure;
|
||||||
|
this._gender = gender;
|
||||||
|
this._name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get objectId(): number
|
||||||
|
{
|
||||||
|
return this._objectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get figure(): string
|
||||||
|
{
|
||||||
|
return this._figure;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get gender(): string
|
||||||
|
{
|
||||||
|
return this._gender;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get name(): string
|
||||||
|
{
|
||||||
|
return this._name;
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,9 @@
|
|||||||
import { RoomWidgetUpdateEvent } from './RoomWidgetUpdateEvent';
|
import { RoomWidgetUpdateEvent } from './RoomWidgetUpdateEvent';
|
||||||
|
|
||||||
export class RoomWidgetRoomEngineUpdateEvent extends RoomWidgetUpdateEvent
|
export class RoomWidgetUpdateRoomEngineEvent extends RoomWidgetUpdateEvent
|
||||||
{
|
{
|
||||||
public static GAME_MODE: string = 'RWREUE_GAME_MODE';
|
public static GAME_MODE: string = 'RWUREE_GAME_MODE';
|
||||||
public static NORMAL_MODE: string = 'RWREUE_NORMAL_MODE';
|
public static NORMAL_MODE: string = 'RWUREE_NORMAL_MODE';
|
||||||
|
|
||||||
private _roomId: number = 0;
|
private _roomId: number = 0;
|
||||||
|
|
@ -1,16 +1,16 @@
|
|||||||
import { RoomWidgetUpdateEvent } from './RoomWidgetUpdateEvent';
|
import { RoomWidgetUpdateEvent } from './RoomWidgetUpdateEvent';
|
||||||
|
|
||||||
export class RoomWidgetRoomObjectUpdateEvent extends RoomWidgetUpdateEvent
|
export class RoomWidgetUpdateRoomObjectEvent extends RoomWidgetUpdateEvent
|
||||||
{
|
{
|
||||||
public static OBJECT_SELECTED: string = 'RWROUE_OBJECT_SELECTED';
|
public static OBJECT_SELECTED: string = 'RWUROE_OBJECT_SELECTED';
|
||||||
public static OBJECT_DESELECTED: string = 'RWROUE_OBJECT_DESELECTED';
|
public static OBJECT_DESELECTED: string = 'RWUROE_OBJECT_DESELECTED';
|
||||||
public static USER_REMOVED: string = 'RWROUE_USER_REMOVED';
|
public static USER_REMOVED: string = 'RWUROE_USER_REMOVED';
|
||||||
public static FURNI_REMOVED: string = 'RWROUE_FURNI_REMOVED';
|
public static FURNI_REMOVED: string = 'RWUROE_FURNI_REMOVED';
|
||||||
public static FURNI_ADDED: string = 'RWROUE_FURNI_ADDED';
|
public static FURNI_ADDED: string = 'RWUROE_FURNI_ADDED';
|
||||||
public static USER_ADDED: string = 'RWROUE_USER_ADDED';
|
public static USER_ADDED: string = 'RWUROE_USER_ADDED';
|
||||||
public static OBJECT_ROLL_OVER: string = 'RWROUE_OBJECT_ROLL_OVER';
|
public static OBJECT_ROLL_OVER: string = 'RWUROE_OBJECT_ROLL_OVER';
|
||||||
public static OBJECT_ROLL_OUT: string = 'RWROUE_OBJECT_ROLL_OUT';
|
public static OBJECT_ROLL_OUT: string = 'RWUROE_OBJECT_ROLL_OUT';
|
||||||
public static OBJECT_REQUEST_MANIPULATION: string = 'RWROUE_OBJECT_REQUEST_MANIPULATION';
|
public static OBJECT_REQUEST_MANIPULATION: string = 'RWUROE_OBJECT_REQUEST_MANIPULATION';
|
||||||
|
|
||||||
private _id: number;
|
private _id: number;
|
||||||
private _category: number;
|
private _category: number;
|
@ -0,0 +1,48 @@
|
|||||||
|
import { RoomWidgetUpdateEvent } from './RoomWidgetUpdateEvent';
|
||||||
|
|
||||||
|
export class RoomWidgetUpdateTrophyEvent extends RoomWidgetUpdateEvent
|
||||||
|
{
|
||||||
|
public static TROPHY_UPDATE: string = 'RWUTE_TROPHY_UPDATE';
|
||||||
|
|
||||||
|
private _color: number;
|
||||||
|
private _name: string;
|
||||||
|
private _date: string;
|
||||||
|
private _message: string;
|
||||||
|
private _extra: number;
|
||||||
|
|
||||||
|
constructor(type: string, color: number, name: string, date: string, message: string, extra: number)
|
||||||
|
{
|
||||||
|
super(type);
|
||||||
|
|
||||||
|
this._color = color;
|
||||||
|
this._name = name;
|
||||||
|
this._date = date;
|
||||||
|
this._message = message;
|
||||||
|
this._extra = extra;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get color(): number
|
||||||
|
{
|
||||||
|
return this._color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get name(): string
|
||||||
|
{
|
||||||
|
return this._name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get date(): string
|
||||||
|
{
|
||||||
|
return this._date;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get message(): string
|
||||||
|
{
|
||||||
|
return this._message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get extra(): number
|
||||||
|
{
|
||||||
|
return this._extra;
|
||||||
|
}
|
||||||
|
}
|
@ -6,8 +6,6 @@ export * from './RoomWidgetChooserContentEvent';
|
|||||||
export * from './RoomWidgetDoorbellEvent';
|
export * from './RoomWidgetDoorbellEvent';
|
||||||
export * from './RoomWidgetFloodControlEvent';
|
export * from './RoomWidgetFloodControlEvent';
|
||||||
export * from './RoomWidgetObjectNameEvent';
|
export * from './RoomWidgetObjectNameEvent';
|
||||||
export * from './RoomWidgetRoomEngineUpdateEvent';
|
|
||||||
export * from './RoomWidgetRoomObjectUpdateEvent';
|
|
||||||
export * from './RoomWidgetUpdateBackgroundColorPreviewEvent';
|
export * from './RoomWidgetUpdateBackgroundColorPreviewEvent';
|
||||||
export * from './RoomWidgetUpdateChatEvent';
|
export * from './RoomWidgetUpdateChatEvent';
|
||||||
export * from './RoomWidgetUpdateChatInputContentEvent';
|
export * from './RoomWidgetUpdateChatInputContentEvent';
|
||||||
@ -24,10 +22,14 @@ export * from './RoomWidgetUpdateInfostandFurniEvent';
|
|||||||
export * from './RoomWidgetUpdateInfostandPetEvent';
|
export * from './RoomWidgetUpdateInfostandPetEvent';
|
||||||
export * from './RoomWidgetUpdateInfostandRentableBotEvent';
|
export * from './RoomWidgetUpdateInfostandRentableBotEvent';
|
||||||
export * from './RoomWidgetUpdateInfostandUserEvent';
|
export * from './RoomWidgetUpdateInfostandUserEvent';
|
||||||
|
export * from './RoomWidgetUpdateMannequinEvent';
|
||||||
export * from './RoomWidgetUpdatePresentDataEvent';
|
export * from './RoomWidgetUpdatePresentDataEvent';
|
||||||
export * from './RoomWidgetUpdateRentableBotChatEvent';
|
export * from './RoomWidgetUpdateRentableBotChatEvent';
|
||||||
|
export * from './RoomWidgetUpdateRoomEngineEvent';
|
||||||
|
export * from './RoomWidgetUpdateRoomObjectEvent';
|
||||||
export * from './RoomWidgetUpdateRoomViewEvent';
|
export * from './RoomWidgetUpdateRoomViewEvent';
|
||||||
export * from './RoomWidgetUpdateSongEvent';
|
export * from './RoomWidgetUpdateSongEvent';
|
||||||
|
export * from './RoomWidgetUpdateTrophyEvent';
|
||||||
export * from './RoomWidgetUpdateUserDataEvent';
|
export * from './RoomWidgetUpdateUserDataEvent';
|
||||||
export * from './RoomWidgetUseProductBubbleEvent';
|
export * from './RoomWidgetUseProductBubbleEvent';
|
||||||
export * from './UseProductItem';
|
export * from './UseProductItem';
|
||||||
|
@ -0,0 +1,54 @@
|
|||||||
|
import { NitroEvent, RoomEngineTriggerWidgetEvent, RoomObjectVariable, RoomWidgetEnum } from '@nitrots/nitro-renderer';
|
||||||
|
import { RoomWidgetUpdateMannequinEvent } from '..';
|
||||||
|
import { GetRoomEngine } from '../../GetRoomEngine';
|
||||||
|
import { RoomWidgetUpdateEvent } from '../events/RoomWidgetUpdateEvent';
|
||||||
|
import { RoomWidgetMessage } from '../messages/RoomWidgetMessage';
|
||||||
|
import { RoomWidgetHandler } from './RoomWidgetHandler';
|
||||||
|
|
||||||
|
export class FurnitureMannequinWidgetHandler extends RoomWidgetHandler
|
||||||
|
{
|
||||||
|
public processEvent(event: NitroEvent): void
|
||||||
|
{
|
||||||
|
switch(event.type)
|
||||||
|
{
|
||||||
|
case RoomEngineTriggerWidgetEvent.REQUEST_MANNEQUIN: {
|
||||||
|
const widgetEvent = (event as RoomEngineTriggerWidgetEvent);
|
||||||
|
const roomObject = GetRoomEngine().getRoomObject(widgetEvent.roomId, widgetEvent.objectId, widgetEvent.category);
|
||||||
|
|
||||||
|
if(!roomObject) return;
|
||||||
|
|
||||||
|
const model = roomObject.model;
|
||||||
|
const figure = model.getValue<string>(RoomObjectVariable.FURNITURE_MANNEQUIN_FIGURE);
|
||||||
|
const gender = model.getValue<string>(RoomObjectVariable.FURNITURE_MANNEQUIN_GENDER);
|
||||||
|
const name = model.getValue<string>(RoomObjectVariable.FURNITURE_MANNEQUIN_NAME);
|
||||||
|
|
||||||
|
this.container.eventDispatcher.dispatchEvent(new RoomWidgetUpdateMannequinEvent(RoomWidgetUpdateMannequinEvent.MANNEQUIN_UPDATE, roomObject.id, figure, gender, name));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public processWidgetMessage(message: RoomWidgetMessage): RoomWidgetUpdateEvent
|
||||||
|
{
|
||||||
|
switch(message.type)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get type(): string
|
||||||
|
{
|
||||||
|
return RoomWidgetEnum.MANNEQUIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get eventTypes(): string[]
|
||||||
|
{
|
||||||
|
return [ RoomEngineTriggerWidgetEvent.REQUEST_MANNEQUIN ];
|
||||||
|
}
|
||||||
|
|
||||||
|
public get messageTypes(): string[]
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,8 @@
|
|||||||
import { AvatarExpressionEnum, HabboClubLevelEnum, NitroEvent, RoomControllerLevel, RoomSessionChatEvent, RoomSettingsComposer, RoomWidgetEnum, RoomZoomEvent, TextureUtils } from '@nitrots/nitro-renderer';
|
import { AvatarExpressionEnum, HabboClubLevelEnum, NitroEvent, RoomControllerLevel, RoomSessionChatEvent, RoomSettingsComposer, RoomWidgetEnum, RoomZoomEvent, TextureUtils } from '@nitrots/nitro-renderer';
|
||||||
import { GetConfiguration, GetNitroInstance } from '../../..';
|
import { GetConfiguration, GetNitroInstance } from '../../..';
|
||||||
import { GetRoomEngine, GetSessionDataManager } from '../../../..';
|
import { GetRoomEngine, GetSessionDataManager } from '../../../..';
|
||||||
|
import { FloorplanEditorEvent } from '../../../../../events/floorplan-editor/FloorplanEditorEvent';
|
||||||
|
import { dispatchUiEvent } from '../../../../../hooks';
|
||||||
import { SendMessageHook } from '../../../../../hooks/messages';
|
import { SendMessageHook } from '../../../../../hooks/messages';
|
||||||
import { RoomWidgetFloodControlEvent, RoomWidgetUpdateEvent } from '../events';
|
import { RoomWidgetFloodControlEvent, RoomWidgetUpdateEvent } from '../events';
|
||||||
import { RoomWidgetChatMessage, RoomWidgetChatSelectAvatarMessage, RoomWidgetChatTypingMessage, RoomWidgetMessage, RoomWidgetRequestWidgetMessage } from '../messages';
|
import { RoomWidgetChatMessage, RoomWidgetChatSelectAvatarMessage, RoomWidgetChatTypingMessage, RoomWidgetMessage, RoomWidgetRequestWidgetMessage } from '../messages';
|
||||||
@ -143,7 +145,8 @@ export class RoomWidgetChatInputHandler extends RoomWidgetHandler
|
|||||||
case ':bcfloor':
|
case ':bcfloor':
|
||||||
if(this.container.roomSession.controllerLevel >= RoomControllerLevel.ROOM_OWNER)
|
if(this.container.roomSession.controllerLevel >= RoomControllerLevel.ROOM_OWNER)
|
||||||
{
|
{
|
||||||
this.container.processWidgetMessage(new RoomWidgetRequestWidgetMessage(RoomWidgetRequestWidgetMessage.FLOOR_EDITOR));
|
//this.container.processWidgetMessage(new RoomWidgetRequestWidgetMessage(RoomWidgetRequestWidgetMessage.FLOOR_EDITOR));
|
||||||
|
dispatchUiEvent(new FloorplanEditorEvent(FloorplanEditorEvent.SHOW_FLOORPLAN_EDITOR));
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -2,6 +2,7 @@ import { IFurnitureData, NitroEvent, ObjectDataFactory, PetFigureData, PetRespec
|
|||||||
import { GetNitroInstance, GetRoomEngine, GetSessionDataManager, IsOwnerOfFurniture } from '../../../..';
|
import { GetNitroInstance, GetRoomEngine, GetSessionDataManager, IsOwnerOfFurniture } from '../../../..';
|
||||||
import { InventoryTradeRequestEvent, WiredSelectObjectEvent } from '../../../../../events';
|
import { InventoryTradeRequestEvent, WiredSelectObjectEvent } from '../../../../../events';
|
||||||
import { FriendsSendFriendRequestEvent } from '../../../../../events/friends/FriendsSendFriendRequestEvent';
|
import { FriendsSendFriendRequestEvent } from '../../../../../events/friends/FriendsSendFriendRequestEvent';
|
||||||
|
import { HelpReportUserEvent } from '../../../../../events/help/HelpReportUserEvent';
|
||||||
import { dispatchUiEvent } from '../../../../../hooks/events';
|
import { dispatchUiEvent } from '../../../../../hooks/events';
|
||||||
import { SendMessageHook } from '../../../../../hooks/messages';
|
import { SendMessageHook } from '../../../../../hooks/messages';
|
||||||
import { PetSupplementEnum } from '../../../../../views/room/widgets/avatar-info/common/PetSupplementEnum';
|
import { PetSupplementEnum } from '../../../../../views/room/widgets/avatar-info/common/PetSupplementEnum';
|
||||||
@ -164,6 +165,7 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
|
|||||||
case RoomWidgetUserActionMessage.REPORT:
|
case RoomWidgetUserActionMessage.REPORT:
|
||||||
return;
|
return;
|
||||||
case RoomWidgetUserActionMessage.REPORT_CFH_OTHER:
|
case RoomWidgetUserActionMessage.REPORT_CFH_OTHER:
|
||||||
|
dispatchUiEvent(new HelpReportUserEvent(userId));
|
||||||
return;
|
return;
|
||||||
case RoomWidgetUserActionMessage.AMBASSADOR_ALERT_USER:
|
case RoomWidgetUserActionMessage.AMBASSADOR_ALERT_USER:
|
||||||
this.container.roomSession.sendAmbassadorAlertMessage(userId);
|
this.container.roomSession.sendAmbassadorAlertMessage(userId);
|
||||||
|
@ -5,6 +5,7 @@ export * from './FurnitureCreditWidgetHandler';
|
|||||||
export * from './FurnitureCustomStackHeightWidgetHandler';
|
export * from './FurnitureCustomStackHeightWidgetHandler';
|
||||||
export * from './FurnitureDimmerWidgetHandler';
|
export * from './FurnitureDimmerWidgetHandler';
|
||||||
export * from './FurnitureExternalImageWidgetHandler';
|
export * from './FurnitureExternalImageWidgetHandler';
|
||||||
|
export * from './FurnitureMannequinWidgetHandler';
|
||||||
export * from './FurniturePresentWidgetHandler';
|
export * from './FurniturePresentWidgetHandler';
|
||||||
export * from './IRoomWidgetHandler';
|
export * from './IRoomWidgetHandler';
|
||||||
export * from './IRoomWidgetHandlerManager';
|
export * from './IRoomWidgetHandlerManager';
|
||||||
|
20
src/api/nitro/session/GetFurnitureData.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { IFurnitureData } from '@nitrots/nitro-renderer';
|
||||||
|
import { GetSessionDataManager } from '.';
|
||||||
|
import { ProductTypeEnum } from '../../../views/catalog/common/ProductTypeEnum';
|
||||||
|
|
||||||
|
export function GetFurnitureData(furniClassId: number, productType: string): IFurnitureData
|
||||||
|
{
|
||||||
|
let furniData: IFurnitureData = null;
|
||||||
|
|
||||||
|
switch(productType.toUpperCase())
|
||||||
|
{
|
||||||
|
case ProductTypeEnum.FLOOR:
|
||||||
|
furniData = GetSessionDataManager().getFloorItemData(furniClassId);
|
||||||
|
break;
|
||||||
|
case ProductTypeEnum.WALL:
|
||||||
|
furniData = GetSessionDataManager().getWallItemData(furniClassId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return furniData;
|
||||||
|
}
|
@ -3,6 +3,7 @@ export * from './CreateRoomSession';
|
|||||||
export * from './GetCanStandUp';
|
export * from './GetCanStandUp';
|
||||||
export * from './GetCanUseExpression';
|
export * from './GetCanUseExpression';
|
||||||
export * from './GetClubMemberLevel';
|
export * from './GetClubMemberLevel';
|
||||||
|
export * from './GetFurnitureData';
|
||||||
export * from './GetFurnitureDataForProductOffer';
|
export * from './GetFurnitureDataForProductOffer';
|
||||||
export * from './GetFurnitureDataForRoomObject';
|
export * from './GetFurnitureDataForRoomObject';
|
||||||
export * from './GetOwnPosture';
|
export * from './GetOwnPosture';
|
||||||
|
BIN
src/assets/images/achievements/back-arrow.png
Normal file
After Width: | Height: | Size: 331 B |
BIN
src/assets/images/floorplaneditor/door-direction-0.png
Normal file
After Width: | Height: | Size: 742 B |
BIN
src/assets/images/floorplaneditor/door-direction-1.png
Normal file
After Width: | Height: | Size: 738 B |
BIN
src/assets/images/floorplaneditor/door-direction-2.png
Normal file
After Width: | Height: | Size: 750 B |
BIN
src/assets/images/floorplaneditor/door-direction-3.png
Normal file
After Width: | Height: | Size: 697 B |
BIN
src/assets/images/floorplaneditor/door-direction-4.png
Normal file
After Width: | Height: | Size: 756 B |
BIN
src/assets/images/floorplaneditor/door-direction-5.png
Normal file
After Width: | Height: | Size: 754 B |
BIN
src/assets/images/floorplaneditor/door-direction-6.png
Normal file
After Width: | Height: | Size: 747 B |
BIN
src/assets/images/floorplaneditor/door-direction-7.png
Normal file
After Width: | Height: | Size: 698 B |
BIN
src/assets/images/floorplaneditor/icon-door.png
Normal file
After Width: | Height: | Size: 806 B |
BIN
src/assets/images/floorplaneditor/icon-tile-down.png
Normal file
After Width: | Height: | Size: 609 B |
BIN
src/assets/images/floorplaneditor/icon-tile-set.png
Normal file
After Width: | Height: | Size: 525 B |
BIN
src/assets/images/floorplaneditor/icon-tile-unset.png
Normal file
After Width: | Height: | Size: 544 B |
BIN
src/assets/images/floorplaneditor/icon-tile-up.png
Normal file
After Width: | Height: | Size: 555 B |
BIN
src/assets/images/floorplaneditor/preview_tile.png
Normal file
After Width: | Height: | Size: 146 B |
BIN
src/assets/images/floorplaneditor/selected_height_icon.png
Normal file
After Width: | Height: | Size: 175 B |
BIN
src/assets/images/help/help_index.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
src/assets/images/loading/connecting-duck-spritesheet.png
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
src/assets/images/loading/connecting_duck_01.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
src/assets/images/loading/connecting_duck_02.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
src/assets/images/loading/connecting_duck_03.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
src/assets/images/loading/connecting_duck_04.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
src/assets/images/loading/connecting_duck_05.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
src/assets/images/loading/connecting_duck_06.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
src/assets/images/loading/connecting_duck_07.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 9.3 KiB |
@ -610,7 +610,7 @@ $aspect-ratios: (
|
|||||||
|
|
||||||
// scss-docs-start font-variables
|
// scss-docs-start font-variables
|
||||||
// stylelint-disable value-keyword-case
|
// stylelint-disable value-keyword-case
|
||||||
$font-family-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !default;
|
$font-family-sans-serif: GameUbuntu, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !default;
|
||||||
$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !default;
|
$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !default;
|
||||||
// stylelint-enable value-keyword-case
|
// stylelint-enable value-keyword-case
|
||||||
$font-family-base: var(--#{$variable-prefix}font-sans-serif) !default;
|
$font-family-base: var(--#{$variable-prefix}font-sans-serif) !default;
|
||||||
@ -1381,15 +1381,15 @@ $form-feedback-tooltip-border-radius: $tooltip-border-radius !default;
|
|||||||
|
|
||||||
// scss-docs-start popover-variables
|
// scss-docs-start popover-variables
|
||||||
$popover-font-size: $font-size-sm !default;
|
$popover-font-size: $font-size-sm !default;
|
||||||
$popover-bg: $white !default;
|
$popover-bg: $light !default;
|
||||||
$popover-max-width: 276px !default;
|
$popover-max-width: 276px !default;
|
||||||
$popover-border-width: $border-width !default;
|
$popover-border-width: $border-width !default;
|
||||||
$popover-border-color: rgba($black, .2) !default;
|
$popover-border-color: $border-color !default;
|
||||||
$popover-border-radius: $border-radius-lg !default;
|
$popover-border-radius: $border-radius !default;
|
||||||
$popover-inner-border-radius: subtract($popover-border-radius, $popover-border-width) !default;
|
$popover-inner-border-radius: subtract($popover-border-radius, $popover-border-width) !default;
|
||||||
$popover-box-shadow: $box-shadow !default;
|
$popover-box-shadow: $box-shadow !default;
|
||||||
|
|
||||||
$popover-header-bg: shade-color($popover-bg, 6%) !default;
|
$popover-header-bg: $primary !default;
|
||||||
$popover-header-color: $headings-color !default;
|
$popover-header-color: $headings-color !default;
|
||||||
$popover-header-padding-y: .5rem !default;
|
$popover-header-padding-y: .5rem !default;
|
||||||
$popover-header-padding-x: $spacer !default;
|
$popover-header-padding-x: $spacer !default;
|
||||||
|
@ -716,6 +716,90 @@
|
|||||||
height: 16px;
|
height: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.icon-hc-banner {
|
||||||
|
background: url("../images/catalog/hc_big.png");
|
||||||
|
width: 68px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-set-tile {
|
||||||
|
background-image: url("../images/floorplaneditor/icon-tile-set.png");
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-unset-tile {
|
||||||
|
background-image: url("../images/floorplaneditor/icon-tile-unset.png");
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-increase-height {
|
||||||
|
background-image: url("../images/floorplaneditor/icon-tile-up.png");
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-decrease-height {
|
||||||
|
background-image: url("../images/floorplaneditor/icon-tile-down.png");
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-set-door {
|
||||||
|
background-image: url("../images/floorplaneditor/icon-door.png");
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-door-direction-0 {
|
||||||
|
background-image: url("../images/floorplaneditor/door-direction-0.png");
|
||||||
|
width: 80px;
|
||||||
|
height: 45px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-door-direction-1 {
|
||||||
|
background-image: url("../images/floorplaneditor/door-direction-1.png");
|
||||||
|
width: 80px;
|
||||||
|
height: 45px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-door-direction-2 {
|
||||||
|
background-image: url("../images/floorplaneditor/door-direction-2.png");
|
||||||
|
width: 80px;
|
||||||
|
height: 45px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-door-direction-3 {
|
||||||
|
background-image: url("../images/floorplaneditor/door-direction-3.png");
|
||||||
|
width: 80px;
|
||||||
|
height: 45px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-door-direction-4 {
|
||||||
|
background-image: url("../images/floorplaneditor/door-direction-4.png");
|
||||||
|
width: 80px;
|
||||||
|
height: 45px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-door-direction-5 {
|
||||||
|
background-image: url("../images/floorplaneditor/door-direction-5.png");
|
||||||
|
width: 80px;
|
||||||
|
height: 45px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-door-direction-6 {
|
||||||
|
background-image: url("../images/floorplaneditor/door-direction-6.png");
|
||||||
|
width: 80px;
|
||||||
|
height: 45px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.icon-door-direction-7 {
|
||||||
|
background-image: url("../images/floorplaneditor/door-direction-7.png");
|
||||||
|
width: 80px;
|
||||||
|
height: 45px;
|
||||||
|
}
|
||||||
|
|
||||||
&.spin {
|
&.spin {
|
||||||
animation: rotating 1s linear infinite;
|
animation: rotating 1s linear infinite;
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.scale-1 {
|
.scale-1 {
|
||||||
transform: scale(1) translateZ(0);
|
transform: scale(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.scale-1-25 {
|
.scale-1-25 {
|
||||||
@ -19,7 +19,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.scale-2 {
|
.scale-2 {
|
||||||
transform: scale(2) translateZ(0);
|
transform: scale(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.opacity-0-5 {
|
.opacity-0-5 {
|
||||||
@ -66,3 +66,7 @@ ul {
|
|||||||
-o-user-select: none;
|
-o-user-select: none;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.grayscale {
|
||||||
|
filter: grayscale(1);
|
||||||
|
}
|
||||||
|
20
src/events/achievements/AchievementsUIUnseenCountEvent.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { NitroEvent } from '@nitrots/nitro-renderer';
|
||||||
|
|
||||||
|
export class AchievementsUIUnseenCountEvent extends NitroEvent
|
||||||
|
{
|
||||||
|
public static UNSEEN_COUNT: string = 'AUUCE_UNSEEN_COUNT';
|
||||||
|
|
||||||
|
private _count: number;
|
||||||
|
|
||||||
|
constructor(count: number)
|
||||||
|
{
|
||||||
|
super(AchievementsUIUnseenCountEvent.UNSEEN_COUNT);
|
||||||
|
|
||||||
|
this._count = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get count(): number
|
||||||
|
{
|
||||||
|
return this._count;
|
||||||
|
}
|
||||||
|
}
|
@ -1 +1,2 @@
|
|||||||
export * from './AchievementsUIEvent';
|
export * from './AchievementsUIEvent';
|
||||||
|
export * from './AchievementsUIUnseenCountEvent';
|
||||||
|
8
src/events/chat-history/ChatHistoryEvent.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { NitroEvent } from '@nitrots/nitro-renderer';
|
||||||
|
|
||||||
|
export class ChatHistoryEvent extends NitroEvent
|
||||||
|
{
|
||||||
|
public static SHOW_CHAT_HISTORY: string = 'CHE_SHOW_CHAT_HISTORY';
|
||||||
|
public static HIDE_CHAT_HISTORY: string = 'CHE_HIDE_CHAT_HISTORY';
|
||||||
|
public static TOGGLE_CHAT_HISTORY: string = 'CHE_TOGGLE_CHAT_HISTORY';
|
||||||
|
}
|
8
src/events/floorplan-editor/FloorplanEditorEvent.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { NitroEvent } from '@nitrots/nitro-renderer';
|
||||||
|
|
||||||
|
export class FloorplanEditorEvent extends NitroEvent
|
||||||
|
{
|
||||||
|
public static SHOW_FLOORPLAN_EDITOR: string = 'FPEE_SHOW_FLOORPLAN_EDITOR';
|
||||||
|
public static HIDE_FLOORPLAN_EDITOR: string = 'FPEE_HIDE_FLOORPLAN_EDITOR';
|
||||||
|
public static TOGGLE_FLOORPLAN_EDITOR: string = 'FPEE_TOGGLE_FLOORPLAN_EDITOR';
|
||||||
|
}
|
8
src/events/help/HelpEvent.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { NitroEvent } from '@nitrots/nitro-renderer';
|
||||||
|
|
||||||
|
export class HelpEvent extends NitroEvent
|
||||||
|
{
|
||||||
|
public static SHOW_HELP_CENTER: string = 'HCE_SHOW_HELP_CENTER';
|
||||||
|
public static HIDE_HELP_CENTER: string = 'HCE_HIDE_HELP_CENTER';
|
||||||
|
public static TOGGLE_HELP_CENTER: string = 'HCE_TOGGLE_HELP_CENTER';
|
||||||
|
}
|
20
src/events/help/HelpReportUserEvent.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { HelpEvent } from './HelpEvent';
|
||||||
|
|
||||||
|
export class HelpReportUserEvent extends HelpEvent
|
||||||
|
{
|
||||||
|
public static REPORT_USER: string = 'HCE_HELP_CENTER_REPORT_USER';
|
||||||
|
|
||||||
|
private _reportedUserId: number;
|
||||||
|
|
||||||
|
constructor(userId: number)
|
||||||
|
{
|
||||||
|
super(HelpReportUserEvent.REPORT_USER);
|
||||||
|
|
||||||
|
this._reportedUserId = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get reportedUserId(): number
|
||||||
|
{
|
||||||
|
return this._reportedUserId;
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,8 @@ export class ModToolsEvent extends NitroEvent
|
|||||||
public static SHOW_MOD_TOOLS: string = 'MTE_SHOW_MOD_TOOLS';
|
public static SHOW_MOD_TOOLS: string = 'MTE_SHOW_MOD_TOOLS';
|
||||||
public static HIDE_MOD_TOOLS: string = 'MTE_HIDE_MOD_TOOLS';
|
public static HIDE_MOD_TOOLS: string = 'MTE_HIDE_MOD_TOOLS';
|
||||||
public static TOGGLE_MOD_TOOLS: string = 'MTE_TOGGLE_MOD_TOOLS';
|
public static TOGGLE_MOD_TOOLS: string = 'MTE_TOGGLE_MOD_TOOLS';
|
||||||
public static SELECT_USER: string = 'MTE_SELECT_USER';
|
|
||||||
public static OPEN_ROOM_INFO: string = 'MTE_OPEN_ROOM_INFO';
|
public static OPEN_ROOM_INFO: string = 'MTE_OPEN_ROOM_INFO';
|
||||||
|
public static OPEN_ROOM_CHATLOG: string = 'MTE_OPEN_ROOM_CHATLOG';
|
||||||
|
public static OPEN_USER_INFO: string = 'MTE_OPEN_USER_INFO';
|
||||||
|
public static OPEN_USER_CHATLOG: string = 'MTE_OPEN_USER_CHATLOG';
|
||||||
}
|
}
|
||||||
|
18
src/events/mod-tools/ModToolsOpenRoomChatlogEvent.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { ModToolsEvent } from './ModToolsEvent';
|
||||||
|
|
||||||
|
export class ModToolsOpenRoomChatlogEvent extends ModToolsEvent
|
||||||
|
{
|
||||||
|
private _roomId: number;
|
||||||
|
|
||||||
|
constructor(roomId: number)
|
||||||
|
{
|
||||||
|
super(ModToolsEvent.OPEN_ROOM_CHATLOG);
|
||||||
|
|
||||||
|
this._roomId = roomId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get roomId(): number
|
||||||
|
{
|
||||||
|
return this._roomId;
|
||||||
|
}
|
||||||
|
}
|
18
src/events/mod-tools/ModToolsOpenUserChatlogEvent.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { ModToolsEvent } from './ModToolsEvent';
|
||||||
|
|
||||||
|
export class ModToolsOpenUserChatlogEvent extends ModToolsEvent
|
||||||
|
{
|
||||||
|
private _userId: number;
|
||||||
|
|
||||||
|
constructor(userId: number)
|
||||||
|
{
|
||||||
|
super(ModToolsEvent.OPEN_USER_CHATLOG);
|
||||||
|
|
||||||
|
this._userId = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get userId(): number
|
||||||
|
{
|
||||||
|
return this._userId;
|
||||||
|
}
|
||||||
|
}
|
18
src/events/mod-tools/ModToolsOpenUserInfoEvent.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { ModToolsEvent } from './ModToolsEvent';
|
||||||
|
|
||||||
|
export class ModToolsOpenUserInfoEvent extends ModToolsEvent
|
||||||
|
{
|
||||||
|
private _userId: number;
|
||||||
|
|
||||||
|
constructor(userId: number)
|
||||||
|
{
|
||||||
|
super(ModToolsEvent.OPEN_USER_INFO);
|
||||||
|
|
||||||
|
this._userId = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get userId(): number
|
||||||
|
{
|
||||||
|
return this._userId;
|
||||||
|
}
|
||||||
|
}
|
@ -1,25 +0,0 @@
|
|||||||
import { ModToolsEvent } from './ModToolsEvent';
|
|
||||||
|
|
||||||
export class ModToolsSelectUserEvent extends ModToolsEvent
|
|
||||||
{
|
|
||||||
private _webID: number;
|
|
||||||
private _name: string;
|
|
||||||
|
|
||||||
constructor(webID: number, name: string)
|
|
||||||
{
|
|
||||||
super(ModToolsEvent.SELECT_USER);
|
|
||||||
|
|
||||||
this._webID = webID;
|
|
||||||
this._name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get webID(): number
|
|
||||||
{
|
|
||||||
return this._webID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get name(): string
|
|
||||||
{
|
|
||||||
return this._name;
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,8 +3,6 @@
|
|||||||
|
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
font-family: GameUbuntu, sans-serif;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
padding: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { ButtonHTMLAttributes, DetailedHTMLProps } from 'react';
|
import { DetailedHTMLProps, HTMLAttributes } from 'react';
|
||||||
import { NitroLayoutOverflow, NitroLayoutPosition, NitroLayoutSpacing } from '../common';
|
import { NitroLayoutOverflow, NitroLayoutPosition, NitroLayoutSpacing } from '../common';
|
||||||
|
|
||||||
export interface NitroLayoutBaseProps extends DetailedHTMLProps<ButtonHTMLAttributes<HTMLDivElement>, HTMLDivElement>
|
export interface NitroLayoutBaseProps extends DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>
|
||||||
{
|
{
|
||||||
overflow?: NitroLayoutOverflow;
|
overflow?: NitroLayoutOverflow;
|
||||||
position?: NitroLayoutPosition;
|
position?: NitroLayoutPosition;
|
||||||
|
19
src/layout/button-group/NitroLayoutButtonGroup.tsx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { FC, useMemo } from 'react';
|
||||||
|
import { NitroLayoutBase } from '../base';
|
||||||
|
import { NitroLayoutButtonGroupProps } from './NitroLayoutButtonGroup.types';
|
||||||
|
|
||||||
|
export const NitroLayoutButtonGroup: FC<NitroLayoutButtonGroupProps> = props =>
|
||||||
|
{
|
||||||
|
const { className = '', ...rest } = props;
|
||||||
|
|
||||||
|
const getClassName = useMemo(() =>
|
||||||
|
{
|
||||||
|
let newClassName = 'btn-group';
|
||||||
|
|
||||||
|
if(className && className.length) newClassName += ` ${ className }`;
|
||||||
|
|
||||||
|
return newClassName;
|
||||||
|
}, [ className ]);
|
||||||
|
|
||||||
|
return <NitroLayoutBase className={ getClassName } { ...rest } />;
|
||||||
|
}
|
6
src/layout/button-group/NitroLayoutButtonGroup.types.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { NitroLayoutBaseProps } from '../base';
|
||||||
|
|
||||||
|
export interface NitroLayoutButtonGroupProps extends NitroLayoutBaseProps
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
2
src/layout/button-group/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './NitroLayoutButtonGroup';
|
||||||
|
export * from './NitroLayoutButtonGroup.types';
|
@ -7,7 +7,7 @@ export const NitroLayoutButton: FC<NitroLayoutButtonProps> = props =>
|
|||||||
|
|
||||||
const getClassName = useMemo(() =>
|
const getClassName = useMemo(() =>
|
||||||
{
|
{
|
||||||
let newClassName = 'btn';
|
let newClassName = 'd-flex justify-content-center align-items-center btn';
|
||||||
|
|
||||||
if(variant && variant.length) newClassName += ` btn-${ variant }`;
|
if(variant && variant.length) newClassName += ` btn-${ variant }`;
|
||||||
|
|
||||||
|
@ -5,11 +5,16 @@ $nitro-card-tabs-height: 33px;
|
|||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
resize: both;
|
resize: both;
|
||||||
|
|
||||||
@import './accordion/NitroCardAccordionView';
|
&.theme-dark {
|
||||||
@import './content/NitroCardContentView';
|
padding: 2px;
|
||||||
@import './grid/NitroCardGridView';
|
background-color: #1C323F;
|
||||||
@import './header/NitroCardHeaderView';
|
border: 2px solid rgba(255, 255, 255, 0.5);
|
||||||
@import './tabs/NitroCardTabsView';
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.theme-primary {
|
||||||
|
border: $border-width solid $border-color;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.nitro-card-responsive {
|
.nitro-card-responsive {
|
||||||
@ -19,10 +24,7 @@ $nitro-card-tabs-height: 33px;
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
overflow: hidden;
|
||||||
.theme-primary {
|
|
||||||
border: $border-width solid $border-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include media-breakpoint-down(lg) {
|
@include media-breakpoint-down(lg) {
|
||||||
|
|
||||||
@ -31,7 +33,7 @@ $nitro-card-tabs-height: 33px;
|
|||||||
left: 0 !important;
|
left: 0 !important;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
transform: none !important;
|
//transform: none !important;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,4 +47,33 @@ $nitro-card-tabs-height: 33px;
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@include media-breakpoint-down(sm) {
|
||||||
|
|
||||||
|
.draggable-window {
|
||||||
|
top: 0 !important;
|
||||||
|
left: 0 !important;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
//transform: none !important;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nitro-card {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: calc(100% - #{$toolbar-height});
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
&.rounded {
|
||||||
|
border-radius: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@import './accordion/NitroCardAccordionView';
|
||||||
|
@import './content/NitroCardContentView';
|
||||||
|
@import './grid/NitroCardGridView';
|
||||||
|
@import './header/NitroCardHeaderView';
|
||||||
|
@import './tabs/NitroCardTabsView';
|
||||||
|
@ -3,6 +3,10 @@
|
|||||||
padding-top: $container-padding-x;
|
padding-top: $container-padding-x;
|
||||||
padding-bottom: $container-padding-x;
|
padding-bottom: $container-padding-x;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
|
||||||
|
&.theme-dark {
|
||||||
|
background-color: #1C323F !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@include media-breakpoint-down(lg) {
|
@include media-breakpoint-down(lg) {
|
||||||
|
@ -4,11 +4,11 @@ import { NitroCardContentViewProps } from './NitroCardContextView.types';
|
|||||||
|
|
||||||
export const NitroCardContentView: FC<NitroCardContentViewProps> = props =>
|
export const NitroCardContentView: FC<NitroCardContentViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { children = null, className = '', ...rest } = props;
|
const { theme = 'primary', children = null, className = '', ...rest } = props;
|
||||||
const { simple = false } = useNitroCardContext();
|
const { simple = false } = useNitroCardContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ `container-fluid bg-light content-area d-flex flex-column overflow-auto ${ (simple ? 'simple' : '') } ${ className || '' }` } { ...rest }>
|
<div className={ `container-fluid ${ theme === 'primary' ? 'bg-light' : ''} content-area d-flex flex-column overflow-auto theme-${theme} ${ (simple ? 'simple' : '') } ${ className || '' }` } { ...rest }>
|
||||||
{ children }
|
{ children }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -2,4 +2,6 @@ import { DetailsHTMLAttributes } from 'react';
|
|||||||
|
|
||||||
|
|
||||||
export interface NitroCardContentViewProps extends DetailsHTMLAttributes<HTMLDivElement>
|
export interface NitroCardContentViewProps extends DetailsHTMLAttributes<HTMLDivElement>
|
||||||
{}
|
{
|
||||||
|
theme?: string;
|
||||||
|
}
|
||||||
|
@ -20,7 +20,7 @@ export const NitroCardGridView: FC<NitroCardGridViewProps> = props =>
|
|||||||
|
|
||||||
if(columns && (columns >= 1))
|
if(columns && (columns >= 1))
|
||||||
{
|
{
|
||||||
newStyle['grid-template-columns'] = 'unset';
|
newStyle.gridTemplateColumns = 'unset';
|
||||||
newStyle['--bs-columns'] = columns.toString();
|
newStyle['--bs-columns'] = columns.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import { NitroCardGridItemViewProps } from './NitroCardGridItemView.types';
|
|||||||
|
|
||||||
export const NitroCardGridItemView: FC<NitroCardGridItemViewProps> = props =>
|
export const NitroCardGridItemView: FC<NitroCardGridItemViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { itemImage = undefined, itemColor = undefined, itemActive = false, itemCount = 1, itemUniqueNumber = -2, itemUnseen = false, className = '', style = {}, children = null, ...rest } = props;
|
const { itemImage = undefined, itemColor = undefined, itemActive = false, itemCount = 1, itemCountMinimum = 1, itemUniqueNumber = -2, itemUnseen = false, className = '', style = {}, children = null, ...rest } = props;
|
||||||
|
|
||||||
const getClassName = useMemo(() =>
|
const getClassName = useMemo(() =>
|
||||||
{
|
{
|
||||||
@ -38,7 +38,7 @@ export const NitroCardGridItemView: FC<NitroCardGridItemViewProps> = props =>
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ getClassName } style={ getStyle } { ...rest }>
|
<div className={ getClassName } style={ getStyle } { ...rest }>
|
||||||
{ (itemCount > 1) &&
|
{ (itemCount > itemCountMinimum) &&
|
||||||
<span className="position-absolute badge border bg-danger px-1 rounded-circle">{ itemCount }</span> }
|
<span className="position-absolute badge border bg-danger px-1 rounded-circle">{ itemCount }</span> }
|
||||||
{ (itemUniqueNumber > 0) &&
|
{ (itemUniqueNumber > 0) &&
|
||||||
<div className="position-absolute unique-item-counter">
|
<div className="position-absolute unique-item-counter">
|
||||||
|
@ -6,6 +6,7 @@ export interface NitroCardGridItemViewProps extends DetailsHTMLAttributes<HTMLDi
|
|||||||
itemColor?: string;
|
itemColor?: string;
|
||||||
itemActive?: boolean;
|
itemActive?: boolean;
|
||||||
itemCount?: number;
|
itemCount?: number;
|
||||||
|
itemCountMinimum?: number;
|
||||||
itemUniqueNumber?: number;
|
itemUniqueNumber?: number;
|
||||||
itemUnseen?: boolean;
|
itemUnseen?: boolean;
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.theme-dark {
|
||||||
|
background-color: #3d5f6e !important;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
.bg-tertiary-split {
|
.bg-tertiary-split {
|
||||||
position: relative;
|
position: relative;
|
||||||
border-bottom: 2px solid darken($quaternary, 5);
|
border-bottom: 2px solid darken($quaternary, 5);
|
||||||
|
@ -4,7 +4,7 @@ import { NitroCardHeaderViewProps } from './NitroCardHeaderView.types';
|
|||||||
|
|
||||||
export const NitroCardHeaderView: FC<NitroCardHeaderViewProps> = props =>
|
export const NitroCardHeaderView: FC<NitroCardHeaderViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { headerText = null, onCloseClick = null } = props;
|
const { headerText = null, onCloseClick = null, theme= 'primary' } = props;
|
||||||
const { simple = false } = useNitroCardContext();
|
const { simple = false } = useNitroCardContext();
|
||||||
|
|
||||||
const onMouseDown = useCallback((event: MouseEvent<HTMLDivElement>) =>
|
const onMouseDown = useCallback((event: MouseEvent<HTMLDivElement>) =>
|
||||||
@ -17,7 +17,7 @@ export const NitroCardHeaderView: FC<NitroCardHeaderViewProps> = props =>
|
|||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
<div className="container-fluid bg-light">
|
<div className="container-fluid bg-light">
|
||||||
<div className="row nitro-card-header simple-header">
|
<div className="row nitro-card-header simple-header overflow-hidden">
|
||||||
<div className="d-flex justify-content-center align-items-center w-100 position-relative px-0">
|
<div className="d-flex justify-content-center align-items-center w-100 position-relative px-0">
|
||||||
<div className="h5 text-white text-center text-shadow bg-tertiary-split border-top-0 drag-handler">{ headerText }</div>
|
<div className="h5 text-white text-center text-shadow bg-tertiary-split border-top-0 drag-handler">{ headerText }</div>
|
||||||
<div className="position-absolute header-close" onMouseDownCapture={ onMouseDown } onClick={ onCloseClick }>
|
<div className="position-absolute header-close" onMouseDownCapture={ onMouseDown } onClick={ onCloseClick }>
|
||||||
@ -31,7 +31,7 @@ export const NitroCardHeaderView: FC<NitroCardHeaderViewProps> = props =>
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="drag-handler container-fluid bg-primary">
|
<div className="drag-handler container-fluid bg-primary">
|
||||||
<div className="row nitro-card-header">
|
<div className={`row nitro-card-header overflow-hidden theme-${theme}`}>
|
||||||
<div className="d-flex justify-content-center align-items-center w-100 position-relative">
|
<div className="d-flex justify-content-center align-items-center w-100 position-relative">
|
||||||
<div className="h4 text-white text-shadow header-text">{ headerText }</div>
|
<div className="h4 text-white text-shadow header-text">{ headerText }</div>
|
||||||
<div className="position-absolute header-close" onMouseDownCapture={ onMouseDown } onClick={ onCloseClick }>
|
<div className="position-absolute header-close" onMouseDownCapture={ onMouseDown } onClick={ onCloseClick }>
|
||||||
|
@ -3,5 +3,6 @@ import { MouseEvent } from 'react';
|
|||||||
export interface NitroCardHeaderViewProps
|
export interface NitroCardHeaderViewProps
|
||||||
{
|
{
|
||||||
headerText: string;
|
headerText: string;
|
||||||
|
theme?: string;
|
||||||
onCloseClick: (event: MouseEvent) => void;
|
onCloseClick: (event: MouseEvent) => void;
|
||||||
}
|
}
|
||||||
|
@ -5,4 +5,5 @@ export * from './grid';
|
|||||||
export * from './header';
|
export * from './header';
|
||||||
export * from './NitroCardView';
|
export * from './NitroCardView';
|
||||||
export * from './NitroCardView.types';
|
export * from './NitroCardView.types';
|
||||||
|
export * from './sub-header';
|
||||||
export * from './tabs';
|
export * from './tabs';
|
||||||
|
21
src/layout/card/sub-header/NitroCardSubHeaderView.tsx
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { FC, useMemo } from 'react';
|
||||||
|
import { NitroLayoutFlex } from '../..';
|
||||||
|
import { NitroCardSubHeaderViewProps } from './NitroCardSubHeaderView.types';
|
||||||
|
|
||||||
|
export const NitroCardSubHeaderView: FC<NitroCardSubHeaderViewProps> = props =>
|
||||||
|
{
|
||||||
|
const { className = '', ...rest } = props;
|
||||||
|
|
||||||
|
const getClassName = useMemo(() =>
|
||||||
|
{
|
||||||
|
let newClassName = 'container-fluid bg-muted justify-content-center py-1';
|
||||||
|
|
||||||
|
if(className && className.length) newClassName += ` ${ className }`;
|
||||||
|
|
||||||
|
return newClassName;
|
||||||
|
}, [ className ]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NitroLayoutFlex className={ getClassName } { ...rest } />
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
import { NitroLayoutFlexProps } from '../../flex';
|
||||||
|
|
||||||
|
export interface NitroCardSubHeaderViewProps extends NitroLayoutFlexProps
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
2
src/layout/card/sub-header/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './NitroCardSubHeaderView';
|
||||||
|
export * from './NitroCardSubHeaderView.types';
|
@ -1 +1 @@
|
|||||||
export type NitroLayoutSpacing = 1 | 2 | 3 | 4 | 5;
|
export type NitroLayoutSpacing = 0 | 1 | 2 | 3 | 4 | 5;
|
||||||
|
@ -1 +1 @@
|
|||||||
export type NitroLayoutVariant = 'primary' | 'success' | 'danger';
|
export type NitroLayoutVariant = 'primary' | 'success' | 'danger' | 'secondary';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { MouseEventType } from '@nitrots/nitro-renderer';
|
import { MouseEventType, TouchEventType } from '@nitrots/nitro-renderer';
|
||||||
import { FC, Key, MouseEvent as ReactMouseEvent, useCallback, useEffect, useRef, useState } from 'react';
|
import { FC, Key, MouseEvent as ReactMouseEvent, TouchEvent as ReactTouchEvent, useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { DraggableWindowPosition, DraggableWindowProps } from './DraggableWindow.types';
|
import { DraggableWindowPosition, DraggableWindowProps } from './DraggableWindow.types';
|
||||||
|
|
||||||
const CURRENT_WINDOWS: HTMLElement[] = [];
|
const CURRENT_WINDOWS: HTMLElement[] = [];
|
||||||
@ -29,7 +29,7 @@ export const DraggableWindow: FC<DraggableWindowProps> = props =>
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onMouseDown = useCallback((event: ReactMouseEvent) =>
|
const moveCurrentWindow = useCallback(() =>
|
||||||
{
|
{
|
||||||
const index = CURRENT_WINDOWS.indexOf(elementRef.current);
|
const index = CURRENT_WINDOWS.indexOf(elementRef.current);
|
||||||
|
|
||||||
@ -50,18 +50,47 @@ export const DraggableWindow: FC<DraggableWindowProps> = props =>
|
|||||||
bringToTop();
|
bringToTop();
|
||||||
}, [ bringToTop ]);
|
}, [ bringToTop ]);
|
||||||
|
|
||||||
const onDragMouseDown = useCallback((event: MouseEvent) =>
|
const onMouseDown = useCallback((event: ReactMouseEvent<HTMLDivElement>) =>
|
||||||
{
|
{
|
||||||
setStart({ x: event.clientX, y: event.clientY });
|
moveCurrentWindow();
|
||||||
|
}, [ moveCurrentWindow ]);
|
||||||
|
|
||||||
|
const onTouchStart = useCallback((event: ReactTouchEvent<HTMLDivElement>) =>
|
||||||
|
{
|
||||||
|
moveCurrentWindow();
|
||||||
|
}, [ moveCurrentWindow ]);
|
||||||
|
|
||||||
|
const startDragging = useCallback((startX: number, startY: number) =>
|
||||||
|
{
|
||||||
|
setStart({ x: startX, y: startY });
|
||||||
setIsDragging(true);
|
setIsDragging(true);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const onDragMouseDown = useCallback((event: MouseEvent) =>
|
||||||
|
{
|
||||||
|
startDragging(event.clientX, event.clientY);
|
||||||
|
}, [ startDragging ]);
|
||||||
|
|
||||||
|
const onTouchDown = useCallback((event: TouchEvent) =>
|
||||||
|
{
|
||||||
|
const touch = event.touches[0];
|
||||||
|
|
||||||
|
startDragging(touch.clientX, touch.clientY);
|
||||||
|
}, [ startDragging ]);
|
||||||
|
|
||||||
const onDragMouseMove = useCallback((event: MouseEvent) =>
|
const onDragMouseMove = useCallback((event: MouseEvent) =>
|
||||||
{
|
{
|
||||||
setDelta({ x: (event.clientX - start.x), y: (event.clientY - start.y) });
|
setDelta({ x: (event.clientX - start.x), y: (event.clientY - start.y) });
|
||||||
}, [ start ]);
|
}, [ start ]);
|
||||||
|
|
||||||
const onDragMouseUp = useCallback((event: MouseEvent) =>
|
const onDragTouchMove = useCallback((event: TouchEvent) =>
|
||||||
|
{
|
||||||
|
const touch = event.touches[0];
|
||||||
|
|
||||||
|
setDelta({ x: (touch.clientX - start.x), y: (touch.clientY - start.y) });
|
||||||
|
}, [ start ]);
|
||||||
|
|
||||||
|
const completeDrag = useCallback(() =>
|
||||||
{
|
{
|
||||||
if(!elementRef.current || !dragHandler) return;
|
if(!elementRef.current || !dragHandler) return;
|
||||||
|
|
||||||
@ -98,6 +127,16 @@ export const DraggableWindow: FC<DraggableWindowProps> = props =>
|
|||||||
if(uniqueKey !== null) POS_MEMORY.set(uniqueKey, { x: offsetX, y: offsetY });
|
if(uniqueKey !== null) POS_MEMORY.set(uniqueKey, { x: offsetX, y: offsetY });
|
||||||
}, [ dragHandler, delta, offset, uniqueKey ]);
|
}, [ dragHandler, delta, offset, uniqueKey ]);
|
||||||
|
|
||||||
|
const onDragMouseUp = useCallback((event: MouseEvent) =>
|
||||||
|
{
|
||||||
|
completeDrag();
|
||||||
|
}, [ completeDrag ]);
|
||||||
|
|
||||||
|
const onDragTouchUp = useCallback((event: TouchEvent) =>
|
||||||
|
{
|
||||||
|
completeDrag();
|
||||||
|
}, [ completeDrag ]);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
const element = (elementRef.current as HTMLElement);
|
const element = (elementRef.current as HTMLElement);
|
||||||
@ -169,29 +208,35 @@ export const DraggableWindow: FC<DraggableWindowProps> = props =>
|
|||||||
if(!dragHandler) return;
|
if(!dragHandler) return;
|
||||||
|
|
||||||
dragHandler.addEventListener(MouseEventType.MOUSE_DOWN, onDragMouseDown);
|
dragHandler.addEventListener(MouseEventType.MOUSE_DOWN, onDragMouseDown);
|
||||||
|
dragHandler.addEventListener(TouchEventType.TOUCH_START, onTouchDown);
|
||||||
|
|
||||||
return () =>
|
return () =>
|
||||||
{
|
{
|
||||||
dragHandler.removeEventListener(MouseEventType.MOUSE_DOWN, onDragMouseDown);
|
dragHandler.removeEventListener(MouseEventType.MOUSE_DOWN, onDragMouseDown);
|
||||||
|
dragHandler.removeEventListener(TouchEventType.TOUCH_START, onTouchDown);
|
||||||
}
|
}
|
||||||
}, [ dragHandler, onDragMouseDown ]);
|
}, [ dragHandler, onDragMouseDown, onTouchDown ]);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
if(!isDragging) return;
|
if(!isDragging) return;
|
||||||
|
|
||||||
document.addEventListener(MouseEventType.MOUSE_UP, onDragMouseUp);
|
document.addEventListener(MouseEventType.MOUSE_UP, onDragMouseUp);
|
||||||
|
document.addEventListener(TouchEventType.TOUCH_END, onDragTouchUp);
|
||||||
document.addEventListener(MouseEventType.MOUSE_MOVE, onDragMouseMove);
|
document.addEventListener(MouseEventType.MOUSE_MOVE, onDragMouseMove);
|
||||||
|
document.addEventListener(TouchEventType.TOUCH_MOVE, onDragTouchMove);
|
||||||
|
|
||||||
return () =>
|
return () =>
|
||||||
{
|
{
|
||||||
document.removeEventListener(MouseEventType.MOUSE_UP, onDragMouseUp);
|
document.removeEventListener(MouseEventType.MOUSE_UP, onDragMouseUp);
|
||||||
|
document.removeEventListener(TouchEventType.TOUCH_END, onDragTouchUp);
|
||||||
document.removeEventListener(MouseEventType.MOUSE_MOVE, onDragMouseMove);
|
document.removeEventListener(MouseEventType.MOUSE_MOVE, onDragMouseMove);
|
||||||
|
document.removeEventListener(TouchEventType.TOUCH_MOVE, onDragTouchMove);
|
||||||
}
|
}
|
||||||
}, [ isDragging, onDragMouseUp, onDragMouseMove ]);
|
}, [ isDragging, onDragMouseUp, onDragMouseMove, onDragTouchUp, onDragTouchMove ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={ elementRef } className="position-absolute draggable-window" onMouseDownCapture={ onMouseDown }>
|
<div ref={ elementRef } className="position-absolute draggable-window" onMouseDownCapture={ onMouseDown } onTouchStartCapture={ onTouchStart }>
|
||||||
{ children }
|
{ children }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
export interface NitroLayoutGiftCardViewProps
|
export interface NitroLayoutGiftCardViewProps
|
||||||
{
|
{
|
||||||
figure?:string;
|
figure?: string;
|
||||||
userName?: string;
|
userName?: string;
|
||||||
message?: string;
|
message?: string;
|
||||||
editable?: boolean;
|
editable?: boolean;
|
||||||
|
@ -4,16 +4,16 @@ import { NitroLayoutGridColumnProps } from './NitroLayoutGridColumn.types';
|
|||||||
|
|
||||||
export const NitroLayoutGridColumn: FC<NitroLayoutGridColumnProps> = props =>
|
export const NitroLayoutGridColumn: FC<NitroLayoutGridColumnProps> = props =>
|
||||||
{
|
{
|
||||||
const { className = '', size = 12, gap = 3, ...rest } = props;
|
const { className = '', size = 12, gap = 2, overflow = 'auto', ...rest } = props;
|
||||||
|
|
||||||
const getClassName = useMemo(() =>
|
const getClassName = useMemo(() =>
|
||||||
{
|
{
|
||||||
let newClassName = `g-col-${ size }`;
|
let newClassName = `g-col-${ size }`;
|
||||||
|
|
||||||
if(className && className.length) newClassName += ' ' + className;
|
if(className && className.length) newClassName += ` ${ className }`;
|
||||||
|
|
||||||
return newClassName;
|
return newClassName;
|
||||||
}, [ className, size ]);
|
}, [ className, size ]);
|
||||||
|
|
||||||
return <NitroLayoutFlexColumn className={ getClassName } gap={ gap } overflow="auto" { ...rest } />
|
return <NitroLayoutFlexColumn className={ getClassName } gap={ gap } overflow={ overflow } { ...rest } />
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
export * from './button';
|
export * from './button';
|
||||||
|
export * from './button-group';
|
||||||
export * from './card';
|
export * from './card';
|
||||||
export * from './common';
|
export * from './common';
|
||||||
export * from './draggable-window';
|
export * from './draggable-window';
|
||||||
|
@ -1,28 +1,46 @@
|
|||||||
import { FC, useEffect, useState } from 'react';
|
import { FC, useEffect, useMemo, useState } from 'react';
|
||||||
|
import { NitroLayoutBase } from '../base';
|
||||||
|
import { TransitionAnimation, TransitionAnimationTypes } from '../transitions';
|
||||||
import { NotificationBubbleViewProps } from './NotificationBubbleView.types';
|
import { NotificationBubbleViewProps } from './NotificationBubbleView.types';
|
||||||
|
|
||||||
export const NotificationBubbleView: FC<NotificationBubbleViewProps> = props =>
|
export const NotificationBubbleView: FC<NotificationBubbleViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { fadesOut = false, close = null, className = '', children = null, ...rest } = props;
|
const { fadesOut = true, timeoutMs = 8000, close = null, className = '', ...rest } = props;
|
||||||
const [ isFading, setIsFading ] = useState(false);
|
const [ isVisible, setIsVisible ] = useState(false);
|
||||||
|
|
||||||
|
const getClassName = useMemo(() =>
|
||||||
|
{
|
||||||
|
let newClassName = 'nitro-notification-bubble rounded';
|
||||||
|
|
||||||
|
if(className && className.length) newClassName += ` ${ className }`;
|
||||||
|
|
||||||
|
return newClassName;
|
||||||
|
}, [ className ]);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
setIsVisible(true);
|
||||||
|
|
||||||
|
return () => setIsVisible(false);
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
if(!fadesOut) return;
|
if(!fadesOut) return;
|
||||||
|
|
||||||
const timeout = setTimeout(() =>
|
const timeout = setTimeout(() =>
|
||||||
{
|
{
|
||||||
setIsFading(true);
|
setIsVisible(false);
|
||||||
|
|
||||||
setTimeout(() => close());
|
setTimeout(() => close(), 300);
|
||||||
}, 8000);
|
}, timeoutMs);
|
||||||
|
|
||||||
return () => clearTimeout(timeout);
|
return () => clearTimeout(timeout);
|
||||||
}, [ fadesOut, close ]);
|
}, [ fadesOut, timeoutMs, close ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ ('nitro-notification-bubble rounded ' + (className || '')) } { ...rest } onClick={ close }>
|
<TransitionAnimation type={ TransitionAnimationTypes.FADE_IN } inProp={ isVisible } timeout={ 300 }>
|
||||||
{ children }
|
<NitroLayoutBase className={ getClassName } onClick={ close } { ...rest } />
|
||||||
</div>
|
</TransitionAnimation>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { DetailsHTMLAttributes } from 'react';
|
import { NitroLayoutBaseProps } from '../base';
|
||||||
|
|
||||||
export interface NotificationBubbleViewProps extends DetailsHTMLAttributes<HTMLDivElement>
|
export interface NotificationBubbleViewProps extends NitroLayoutBaseProps
|
||||||
{
|
{
|
||||||
fadesOut?: boolean;
|
fadesOut?: boolean;
|
||||||
|
timeoutMs?: number;
|
||||||
close: () => void;
|
close: () => void;
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
width: 340px;
|
width: 340px;
|
||||||
height: 173px;
|
height: 173px;
|
||||||
color: black;
|
color: black;
|
||||||
|
pointer-events: all;
|
||||||
|
|
||||||
background-position: 0px 0px;
|
background-position: 0px 0px;
|
||||||
background-image: url('../../assets/images/room-widgets/trophy-widget/trophy-spritesheet.png');
|
background-image: url('../../assets/images/room-widgets/trophy-widget/trophy-spritesheet.png');
|
||||||
|
@ -20,3 +20,6 @@
|
|||||||
@import './achievements/AchievementsView';
|
@import './achievements/AchievementsView';
|
||||||
@import './user-settings/UserSettingsView';
|
@import './user-settings/UserSettingsView';
|
||||||
@import './user-profile/UserProfileVew';
|
@import './user-profile/UserProfileVew';
|
||||||
|
@import './chat-history/ChatHistoryView';
|
||||||
|
@import './help/HelpView';
|
||||||
|
@import './floorplan-editor/FloorplanEditorView';
|
||||||
|
@ -1,70 +0,0 @@
|
|||||||
import { AchievementEvent, AchievementsEvent, AchievementsScoreEvent } from '@nitrots/nitro-renderer';
|
|
||||||
import { FC, useCallback } from 'react';
|
|
||||||
import { CreateMessageHook } from '../../hooks/messages';
|
|
||||||
import { IAchievementsMessageHandlerProps } from './AchievementsMessageHandler.types';
|
|
||||||
import { AchievementCategory } from './common/AchievementCategory';
|
|
||||||
import { useAchievementsContext } from './context/AchievementsContext';
|
|
||||||
import { AchievementsActions } from './reducers/AchievementsReducer';
|
|
||||||
|
|
||||||
export const AchievementsMessageHandler: FC<IAchievementsMessageHandlerProps> = props =>
|
|
||||||
{
|
|
||||||
const { achievementsState = null, dispatchAchievementsState = null } = useAchievementsContext();
|
|
||||||
|
|
||||||
const onAchievementEvent = useCallback((event: AchievementEvent) =>
|
|
||||||
{
|
|
||||||
const parser = event.getParser();
|
|
||||||
|
|
||||||
console.log(parser);
|
|
||||||
|
|
||||||
}, [ dispatchAchievementsState ]);
|
|
||||||
|
|
||||||
const onAchievementsEvent = useCallback((event: AchievementsEvent) =>
|
|
||||||
{
|
|
||||||
const parser = event.getParser();
|
|
||||||
|
|
||||||
const categories: AchievementCategory[] = [];
|
|
||||||
|
|
||||||
for(const achievement of parser.achievements)
|
|
||||||
{
|
|
||||||
const categoryName = achievement.category;
|
|
||||||
|
|
||||||
const existing = categories.find(category => category.name === categoryName);
|
|
||||||
|
|
||||||
if(existing)
|
|
||||||
{
|
|
||||||
existing.achievements.push(achievement);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const category = new AchievementCategory(categoryName);
|
|
||||||
category.achievements.push(achievement);
|
|
||||||
categories.push(category);
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatchAchievementsState({
|
|
||||||
type: AchievementsActions.SET_CATEGORIES,
|
|
||||||
payload: {
|
|
||||||
categories: categories
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, [ dispatchAchievementsState ]);
|
|
||||||
|
|
||||||
const onAchievementsScoreEvent = useCallback((event: AchievementsScoreEvent) =>
|
|
||||||
{
|
|
||||||
const parser = event.getParser();
|
|
||||||
|
|
||||||
dispatchAchievementsState({
|
|
||||||
type: AchievementsActions.SET_SCORE,
|
|
||||||
payload: {
|
|
||||||
score: parser.score
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}, [ dispatchAchievementsState ]);
|
|
||||||
|
|
||||||
CreateMessageHook(AchievementEvent, onAchievementEvent);
|
|
||||||
CreateMessageHook(AchievementsEvent, onAchievementsEvent);
|
|
||||||
CreateMessageHook(AchievementsScoreEvent, onAchievementsScoreEvent);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
};
|
|
@ -1,2 +0,0 @@
|
|||||||
export interface IAchievementsMessageHandlerProps
|
|
||||||
{}
|
|
@ -1,63 +1,28 @@
|
|||||||
.nitro-achievements {
|
.nitro-achievements {
|
||||||
width: $achievement-width;
|
width: $achievement-width;
|
||||||
height: $achievement-height;
|
height: $achievement-height;
|
||||||
|
}
|
||||||
|
|
||||||
.score {
|
.nitro-achievements-category-grid {
|
||||||
border-color: $grid-border-color !important;
|
--nitro-grid-column-min-width: 80px !important;
|
||||||
background-color: $grid-bg-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.category {
|
.grid-item {
|
||||||
border-color: $grid-border-color !important;
|
|
||||||
background-color: $grid-bg-color;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
border-color: $grid-active-border-color !important;
|
|
||||||
background-color: $grid-active-bg-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.category-score {
|
|
||||||
margin-top: 43.5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.achievements {
|
|
||||||
height: 152px;
|
|
||||||
overflow-y: auto;
|
|
||||||
overflow-x: hidden;
|
|
||||||
|
|
||||||
.achievement {
|
|
||||||
border-color: $grid-border-color !important;
|
|
||||||
background-color: $grid-bg-color;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
border-color: $grid-active-border-color !important;
|
|
||||||
background-color: $grid-active-bg-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.gray {
|
|
||||||
div {
|
|
||||||
filter: grayscale(1);
|
|
||||||
opacity: .5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
div {
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.achievement-image {
|
|
||||||
height: 80px;
|
height: 80px;
|
||||||
width: 80px;
|
max-height: 80px;
|
||||||
|
|
||||||
.badge-image {
|
.achievement-score {
|
||||||
width: 80px;
|
top: 50px;
|
||||||
height: 80px;
|
|
||||||
background-size: contain;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nitro-achievements-back-arrow {
|
||||||
|
background: url('../../assets/images/achievements/back-arrow.png') no-repeat center;
|
||||||
|
width: 33px;
|
||||||
|
height: 34px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nitro-achievements-badge-image {
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
}
|
||||||
|
@ -1,22 +1,26 @@
|
|||||||
import { FC, useCallback, useReducer, useState } from 'react';
|
import { AchievementData, AchievementEvent, AchievementsEvent, AchievementsScoreEvent, RequestAchievementsMessageComposer } from '@nitrots/nitro-renderer';
|
||||||
|
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { LocalizeText } from '../../api';
|
import { LocalizeText } from '../../api';
|
||||||
import { AchievementsUIEvent } from '../../events/achievements';
|
import { AchievementsUIEvent, AchievementsUIUnseenCountEvent } from '../../events/achievements';
|
||||||
|
import { BatchUpdates, CreateMessageHook, dispatchUiEvent, SendMessageHook } from '../../hooks';
|
||||||
import { useUiEvent } from '../../hooks/events';
|
import { useUiEvent } from '../../hooks/events';
|
||||||
import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../layout';
|
import { NitroCardContentView, NitroCardHeaderView, NitroCardSubHeaderView, NitroCardView, NitroLayoutFlexColumn, NitroLayoutGrid, NitroLayoutGridColumn } from '../../layout';
|
||||||
import { AchievementsMessageHandler } from './AchievementsMessageHandler';
|
import { NitroLayoutBase } from '../../layout/base';
|
||||||
import { AchievementsViewProps } from './AchievementsView.types';
|
import { AchievementsViewProps } from './AchievementsView.types';
|
||||||
import { AchievementsContextProvider } from './context/AchievementsContext';
|
import { AchievementCategory } from './common/AchievementCategory';
|
||||||
import { AchievementsReducer, initialAchievements } from './reducers/AchievementsReducer';
|
import { AchievementUtilities } from './common/AchievementUtilities';
|
||||||
import { AchievementsListView } from './views/category-list/AchievementsListView';
|
import { AchievementsCategoryListView } from './views/category-list/AchievementsCategoryListView';
|
||||||
import { AchievementCategoryView } from './views/category/AchievementCategoryView';
|
import { AchievementCategoryView } from './views/category/AchievementCategoryView';
|
||||||
|
|
||||||
export const AchievementsView: FC<AchievementsViewProps> = props =>
|
export const AchievementsView: FC<AchievementsViewProps> = props =>
|
||||||
{
|
{
|
||||||
const [ isVisible, setIsVisible ] = useState(false);
|
const [ isVisible, setIsVisible ] = useState(false);
|
||||||
const [ achievementsState, dispatchAchievementsState ] = useReducer(AchievementsReducer, initialAchievements);
|
const [ isInitalized, setIsInitalized ] = useState(false);
|
||||||
const { score = null } = achievementsState;
|
const [ achievementCategories, setAchievementCategories ] = useState<AchievementCategory[]>([]);
|
||||||
|
const [ selectedCategoryCode, setSelectedCategoryCode ] = useState<string>(null);
|
||||||
|
const [ achievementScore, setAchievementScore ] = useState(0);
|
||||||
|
|
||||||
const onAchievementsEvent = useCallback((event: AchievementsUIEvent) =>
|
const onAchievementsUIEvent = useCallback((event: AchievementsUIEvent) =>
|
||||||
{
|
{
|
||||||
switch(event.type)
|
switch(event.type)
|
||||||
{
|
{
|
||||||
@ -32,30 +36,210 @@ export const AchievementsView: FC<AchievementsViewProps> = props =>
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useUiEvent(AchievementsUIEvent.SHOW_ACHIEVEMENTS, onAchievementsEvent);
|
useUiEvent(AchievementsUIEvent.SHOW_ACHIEVEMENTS, onAchievementsUIEvent);
|
||||||
useUiEvent(AchievementsUIEvent.HIDE_ACHIEVEMENTS, onAchievementsEvent);
|
useUiEvent(AchievementsUIEvent.HIDE_ACHIEVEMENTS, onAchievementsUIEvent);
|
||||||
useUiEvent(AchievementsUIEvent.TOGGLE_ACHIEVEMENTS, onAchievementsEvent);
|
useUiEvent(AchievementsUIEvent.TOGGLE_ACHIEVEMENTS, onAchievementsUIEvent);
|
||||||
|
|
||||||
|
const onAchievementEvent = useCallback((event: AchievementEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
const achievement = parser.achievement;
|
||||||
|
const newCategories = [ ...achievementCategories ];
|
||||||
|
const categoryName = achievement.category;
|
||||||
|
const categoryIndex = newCategories.findIndex(existing => (existing.code === categoryName));
|
||||||
|
|
||||||
|
if(categoryIndex === -1)
|
||||||
|
{
|
||||||
|
const category = new AchievementCategory(categoryName);
|
||||||
|
|
||||||
|
category.achievements.push(achievement);
|
||||||
|
|
||||||
|
newCategories.push(category);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const category = newCategories[categoryIndex];
|
||||||
|
const newAchievements = [ ...category.achievements ];
|
||||||
|
const achievementIndex = newAchievements.findIndex(existing => (existing.achievementId === achievement.achievementId));
|
||||||
|
let previousAchievement: AchievementData = null;
|
||||||
|
|
||||||
|
if(achievementIndex === -1)
|
||||||
|
{
|
||||||
|
newAchievements.push(achievement);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
previousAchievement = newAchievements[achievementIndex];
|
||||||
|
|
||||||
|
newAchievements[achievementIndex] = achievement;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!AchievementUtilities.isIgnoredAchievement(achievement))
|
||||||
|
{
|
||||||
|
achievement.unseen++;
|
||||||
|
|
||||||
|
if(previousAchievement) achievement.unseen += previousAchievement.unseen;
|
||||||
|
}
|
||||||
|
|
||||||
|
category.achievements = newAchievements;
|
||||||
|
}
|
||||||
|
|
||||||
|
setAchievementCategories(newCategories);
|
||||||
|
}, [ achievementCategories ]);
|
||||||
|
|
||||||
|
CreateMessageHook(AchievementEvent, onAchievementEvent);
|
||||||
|
|
||||||
|
const onAchievementsEvent = useCallback((event: AchievementsEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
|
||||||
|
const categories: AchievementCategory[] = [];
|
||||||
|
|
||||||
|
for(const achievement of parser.achievements)
|
||||||
|
{
|
||||||
|
const categoryName = achievement.category;
|
||||||
|
let existing = categories.find(category => (category.code === categoryName));
|
||||||
|
|
||||||
|
if(!existing)
|
||||||
|
{
|
||||||
|
existing = new AchievementCategory(categoryName);
|
||||||
|
|
||||||
|
categories.push(existing);
|
||||||
|
}
|
||||||
|
|
||||||
|
existing.achievements.push(achievement);
|
||||||
|
}
|
||||||
|
|
||||||
|
BatchUpdates(() =>
|
||||||
|
{
|
||||||
|
setAchievementCategories(categories);
|
||||||
|
setIsInitalized(true);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
CreateMessageHook(AchievementsEvent, onAchievementsEvent);
|
||||||
|
|
||||||
|
const onAchievementsScoreEvent = useCallback((event: AchievementsScoreEvent) =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
|
||||||
|
setAchievementScore(parser.score);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
CreateMessageHook(AchievementsScoreEvent, onAchievementsScoreEvent);
|
||||||
|
|
||||||
|
const getTotalUnseen = useMemo(() =>
|
||||||
|
{
|
||||||
|
let unseen = 0;
|
||||||
|
|
||||||
|
for(const category of achievementCategories)
|
||||||
|
{
|
||||||
|
for(const achievement of category.achievements) unseen += achievement.unseen;
|
||||||
|
}
|
||||||
|
|
||||||
|
return unseen;
|
||||||
|
}, [ achievementCategories ]);
|
||||||
|
|
||||||
|
const getProgress = useMemo(() =>
|
||||||
|
{
|
||||||
|
let progress = 0;
|
||||||
|
|
||||||
|
for(const category of achievementCategories) progress += category.getProgress();
|
||||||
|
|
||||||
|
return progress;
|
||||||
|
}, [ achievementCategories ]);
|
||||||
|
|
||||||
|
const getMaxProgress = useMemo(() =>
|
||||||
|
{
|
||||||
|
let progress = 0;
|
||||||
|
|
||||||
|
for(const category of achievementCategories) progress += category.getMaxProgress();
|
||||||
|
|
||||||
|
return progress;
|
||||||
|
}, [ achievementCategories ]);
|
||||||
|
|
||||||
|
const scaledProgressPercent = useMemo(() =>
|
||||||
|
{
|
||||||
|
return ~~((((getProgress - 0) * (100 - 0)) / (getMaxProgress - 0)) + 0);
|
||||||
|
}, [ getProgress, getMaxProgress ]);
|
||||||
|
|
||||||
|
const getSelectedCategory = useMemo(() =>
|
||||||
|
{
|
||||||
|
if(!achievementCategories || !achievementCategories.length) return null;
|
||||||
|
|
||||||
|
return achievementCategories.find(existing => (existing.code === selectedCategoryCode));
|
||||||
|
}, [ achievementCategories, selectedCategoryCode ]);
|
||||||
|
|
||||||
|
const setAchievementSeen = useCallback((code: string, achievementId: number) =>
|
||||||
|
{
|
||||||
|
const newCategories = [ ...achievementCategories ];
|
||||||
|
|
||||||
|
for(const category of newCategories)
|
||||||
|
{
|
||||||
|
if(category.code !== code) continue;
|
||||||
|
|
||||||
|
for(const achievement of category.achievements)
|
||||||
|
{
|
||||||
|
if(achievement.achievementId !== achievementId) continue;
|
||||||
|
|
||||||
|
achievement.unseen = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setAchievementCategories(newCategories);
|
||||||
|
}, [ achievementCategories ]);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
if(!isVisible || !isInitalized) return;
|
||||||
|
|
||||||
|
SendMessageHook(new RequestAchievementsMessageComposer());
|
||||||
|
}, [ isVisible, isInitalized ]);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
dispatchUiEvent(new AchievementsUIUnseenCountEvent(getTotalUnseen));
|
||||||
|
}, [ getTotalUnseen ]);
|
||||||
|
|
||||||
|
if(!isVisible || !isInitalized) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AchievementsContextProvider value={ { achievementsState, dispatchAchievementsState } }>
|
<NitroCardView uniqueKey="achievements" className="nitro-achievements" simple={ true }>
|
||||||
<AchievementsMessageHandler />
|
<NitroCardHeaderView headerText={ LocalizeText('inventory.achievements') } onCloseClick={ event => setIsVisible(false) } />
|
||||||
{ isVisible &&
|
{ getSelectedCategory &&
|
||||||
<NitroCardView uniqueKey="achievements" className="nitro-achievements" simple={ true }>
|
<NitroCardSubHeaderView className="justify-content-center align-items-center cursor-pointer" gap={ 3 }>
|
||||||
<NitroCardHeaderView headerText={ LocalizeText('inventory.achievements') } onCloseClick={ event => setIsVisible(false) } />
|
<NitroLayoutBase onClick={ event => setSelectedCategoryCode(null) } className="nitro-achievements-back-arrow" />
|
||||||
<NitroCardContentView>
|
<NitroLayoutFlexColumn className="flex-grow-1">
|
||||||
<div className="row">
|
<NitroLayoutBase className="fs-4 text-black fw-bold">
|
||||||
<div className="col-6">
|
{ LocalizeText(`quests.${ getSelectedCategory.code }.name`) }
|
||||||
<AchievementsListView />
|
</NitroLayoutBase>
|
||||||
<div className="score border border-2 text-black text-center rounded">
|
<NitroLayoutBase className="text-black">
|
||||||
{ LocalizeText('achievements.categories.score', ['score'], [score.toString()]) }
|
{ LocalizeText('achievements.details.categoryprogress', [ 'progress', 'limit' ], [ getSelectedCategory.getProgress().toString(), getSelectedCategory.getMaxProgress().toString() ]) }
|
||||||
</div>
|
</NitroLayoutBase>
|
||||||
</div>
|
</NitroLayoutFlexColumn>
|
||||||
<div className="col-6">
|
</NitroCardSubHeaderView> }
|
||||||
<AchievementCategoryView />
|
<NitroCardContentView>
|
||||||
</div>
|
<NitroLayoutGrid>
|
||||||
</div>
|
<NitroLayoutGridColumn size={ 12 }>
|
||||||
</NitroCardContentView>
|
{ !getSelectedCategory &&
|
||||||
</NitroCardView> }
|
<>
|
||||||
</AchievementsContextProvider>
|
<AchievementsCategoryListView categories={ achievementCategories } selectedCategoryCode={ selectedCategoryCode } setSelectedCategoryCode={ setSelectedCategoryCode } />
|
||||||
|
<NitroLayoutFlexColumn className="flex-grow-1 justify-content-end" gap={ 2 }>
|
||||||
|
<NitroLayoutBase className="progress">
|
||||||
|
<NitroLayoutBase className="progress-bar" style={ { width: (scaledProgressPercent + '%') }}>
|
||||||
|
{ LocalizeText('achievements.categories.totalprogress', [ 'progress', 'limit' ], [ getProgress.toString(), getMaxProgress.toString() ]) }
|
||||||
|
</NitroLayoutBase>
|
||||||
|
</NitroLayoutBase>
|
||||||
|
<NitroLayoutBase className="bg-muted text-black text-center rounded">
|
||||||
|
{ LocalizeText('achievements.categories.score', [ 'score' ], [ achievementScore.toString() ]) }
|
||||||
|
</NitroLayoutBase>
|
||||||
|
</NitroLayoutFlexColumn>
|
||||||
|
</> }
|
||||||
|
{ getSelectedCategory &&
|
||||||
|
<AchievementCategoryView category={ getSelectedCategory } setAchievementSeen={ setAchievementSeen } /> }
|
||||||
|
</NitroLayoutGridColumn>
|
||||||
|
</NitroLayoutGrid>
|
||||||
|
</NitroCardContentView>
|
||||||
|
</NitroCardView>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -2,23 +2,42 @@ import { AchievementData } from '@nitrots/nitro-renderer';
|
|||||||
|
|
||||||
export class AchievementCategory
|
export class AchievementCategory
|
||||||
{
|
{
|
||||||
private _name: string;
|
private _code: string;
|
||||||
private _achievements: AchievementData[];
|
private _achievements: AchievementData[];
|
||||||
|
|
||||||
constructor(name: string)
|
constructor(code: string)
|
||||||
{
|
{
|
||||||
this._name = name;
|
this._code = code;
|
||||||
this._achievements = [];
|
this._achievements = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public get name(): string
|
public getProgress(): number
|
||||||
{
|
{
|
||||||
return this._name;
|
let progress = 0;
|
||||||
|
|
||||||
|
for(const achievement of this._achievements)
|
||||||
|
{
|
||||||
|
progress += (achievement.finalLevel ? achievement.level : (achievement.level - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
return progress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public set name(name: string)
|
public getMaxProgress(): number
|
||||||
{
|
{
|
||||||
this._name = name;
|
let progress = 0;
|
||||||
|
|
||||||
|
for(const achievement of this._achievements)
|
||||||
|
{
|
||||||
|
progress += achievement.levelCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
return progress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get code(): string
|
||||||
|
{
|
||||||
|
return this._code;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get achievements(): AchievementData[]
|
public get achievements(): AchievementData[]
|
||||||
|
38
src/views/achievements/common/AchievementUtilities.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { AchievementData } from '@nitrots/nitro-renderer';
|
||||||
|
import { GetConfiguration, GetLocalization } from '../../../api';
|
||||||
|
|
||||||
|
export class AchievementUtilities
|
||||||
|
{
|
||||||
|
public static hasStarted(achievement: AchievementData): boolean
|
||||||
|
{
|
||||||
|
if(!achievement) return false;
|
||||||
|
|
||||||
|
if(achievement.finalLevel || ((achievement.level - 1) > 0)) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getBadgeCode(achievement: AchievementData): string
|
||||||
|
{
|
||||||
|
if(!achievement) return null;
|
||||||
|
|
||||||
|
let badgeId = achievement.badgeId;
|
||||||
|
|
||||||
|
if(!achievement.finalLevel) badgeId = GetLocalization().getPreviousLevelBadgeId(badgeId);
|
||||||
|
|
||||||
|
return badgeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static isIgnoredAchievement(achievement: AchievementData): boolean
|
||||||
|
{
|
||||||
|
if(!achievement) return false;
|
||||||
|
|
||||||
|
const ignored = GetConfiguration<string[]>('achievements.unseen.ignored');
|
||||||
|
const value = achievement.badgeId.replace(/[0-9]/g, '');
|
||||||
|
const index = ignored.indexOf(value);
|
||||||
|
|
||||||
|
if(index >= 0) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
8
src/views/achievements/common/GetAchievementLevel.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { AchievementData } from '@nitrots/nitro-renderer';
|
||||||
|
|
||||||
|
export const GetAchievementLevel = (achievement: AchievementData) =>
|
||||||
|
{
|
||||||
|
if(achievement.finalLevel) return achievement.level;
|
||||||
|
|
||||||
|
return (achievement.level - 1);
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
import { AchievementData } from '@nitrots/nitro-renderer';
|
||||||
|
|
||||||
|
export const GetScaledProgressPercent = (achievement: AchievementData) =>
|
||||||
|
{
|
||||||
|
if(!achievement) return 0;
|
||||||
|
|
||||||
|
return ~~(((((achievement.currentPoints + achievement.scoreAtStartOfLevel) - 0) * (100 - 0)) / ((achievement.scoreLimit + achievement.scoreAtStartOfLevel) - 0)) + 0);
|
||||||
|
}
|
15
src/views/achievements/common/IsIgnoredAchievement.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { AchievementData } from '@nitrots/nitro-renderer';
|
||||||
|
import { GetConfiguration } from '../../../api';
|
||||||
|
|
||||||
|
export const IsIgnoredAchievement = (achievement: AchievementData) =>
|
||||||
|
{
|
||||||
|
if(!achievement) return false;
|
||||||
|
|
||||||
|
const ignored = GetConfiguration<string[]>('achievements.unseen.ignored');
|
||||||
|
const value = achievement.badgeId.replace(/[0-9]/g, '');
|
||||||
|
const index = ignored.indexOf(value);
|
||||||
|
|
||||||
|
if(index >= 0) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
@ -1,14 +0,0 @@
|
|||||||
import { createContext, FC, useContext } from 'react';
|
|
||||||
import { AchievementsContextProps, IAchievementsContext } from './AchievementsContext.types';
|
|
||||||
|
|
||||||
const AchievementsContext = createContext<IAchievementsContext>({
|
|
||||||
achievementsState: null,
|
|
||||||
dispatchAchievementsState: null
|
|
||||||
});
|
|
||||||
|
|
||||||
export const AchievementsContextProvider: FC<AchievementsContextProps> = props =>
|
|
||||||
{
|
|
||||||
return <AchievementsContext.Provider value={ props.value }>{ props.children }</AchievementsContext.Provider>
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useAchievementsContext = () => useContext(AchievementsContext);
|
|
@ -1,13 +0,0 @@
|
|||||||
import { Dispatch, ProviderProps } from 'react';
|
|
||||||
import { IAchievementsAction, IAchievementsState } from '../reducers/AchievementsReducer';
|
|
||||||
|
|
||||||
export interface IAchievementsContext
|
|
||||||
{
|
|
||||||
achievementsState: IAchievementsState;
|
|
||||||
dispatchAchievementsState: Dispatch<IAchievementsAction>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AchievementsContextProps extends ProviderProps<IAchievementsContext>
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
@ -1,87 +0,0 @@
|
|||||||
import { Reducer } from 'react';
|
|
||||||
import { AchievementCategory } from '../common/AchievementCategory';
|
|
||||||
|
|
||||||
export interface IAchievementsState
|
|
||||||
{
|
|
||||||
categories: AchievementCategory[],
|
|
||||||
score: number,
|
|
||||||
selectedCategoryName: string,
|
|
||||||
selectedAchievementId: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IAchievementsAction
|
|
||||||
{
|
|
||||||
type: string;
|
|
||||||
payload: {
|
|
||||||
categories?: AchievementCategory[],
|
|
||||||
score?: number,
|
|
||||||
selectedCategoryName?: string,
|
|
||||||
selectedAchievementId?: number
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AchievementsActions
|
|
||||||
{
|
|
||||||
public static SET_CATEGORIES: string = 'AA_SET_CATEGORIES';
|
|
||||||
public static SET_SCORE: string = 'AA_SET_SCORE';
|
|
||||||
public static SELECT_CATEGORY: string = 'AA_SELECT_CATEGORY';
|
|
||||||
public static SELECT_ACHIEVEMENT: string = 'AA_SELECT_ACHIEVEMENT';
|
|
||||||
}
|
|
||||||
|
|
||||||
export const initialAchievements: IAchievementsState = {
|
|
||||||
categories: null,
|
|
||||||
score: null,
|
|
||||||
selectedCategoryName: null,
|
|
||||||
selectedAchievementId: null
|
|
||||||
}
|
|
||||||
|
|
||||||
export const AchievementsReducer: Reducer<IAchievementsState, IAchievementsAction> = (state, action) =>
|
|
||||||
{
|
|
||||||
switch(action.type)
|
|
||||||
{
|
|
||||||
case AchievementsActions.SET_CATEGORIES: {
|
|
||||||
const categories = (action.payload.categories || state.categories || null);
|
|
||||||
|
|
||||||
let selectedCategoryName = null;
|
|
||||||
let selectedAchievementId = null;
|
|
||||||
|
|
||||||
if(categories.length > 0)
|
|
||||||
{
|
|
||||||
selectedCategoryName = categories[0].name;
|
|
||||||
|
|
||||||
if(categories[0].achievements.length > 0) selectedAchievementId = categories[0].achievements[0].achievementId;
|
|
||||||
}
|
|
||||||
|
|
||||||
return { ...state, categories, selectedCategoryName, selectedAchievementId };
|
|
||||||
}
|
|
||||||
case AchievementsActions.SET_SCORE: {
|
|
||||||
const score = (action.payload.score || state.score || null);
|
|
||||||
|
|
||||||
return { ...state, score };
|
|
||||||
}
|
|
||||||
case AchievementsActions.SELECT_CATEGORY: {
|
|
||||||
const selectedCategoryName = (action.payload.selectedCategoryName || state.selectedCategoryName || null);
|
|
||||||
|
|
||||||
let selectedAchievementId = null;
|
|
||||||
|
|
||||||
if(selectedCategoryName)
|
|
||||||
{
|
|
||||||
const category = state.categories.find(category => category.name === selectedCategoryName);
|
|
||||||
|
|
||||||
if(category && category.achievements.length > 0)
|
|
||||||
{
|
|
||||||
selectedAchievementId = category.achievements[0].achievementId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return { ...state, selectedCategoryName, selectedAchievementId };
|
|
||||||
}
|
|
||||||
case AchievementsActions.SELECT_ACHIEVEMENT: {
|
|
||||||
const selectedAchievementId = (action.payload.selectedAchievementId || state.selectedAchievementId || null);
|
|
||||||
|
|
||||||
return { ...state, selectedAchievementId };
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,15 @@
|
|||||||
|
import { FC } from 'react';
|
||||||
|
import { BadgeImageView } from '../../../shared/badge-image/BadgeImageView';
|
||||||
|
import { AchievementUtilities } from '../../common/AchievementUtilities';
|
||||||
|
import { AchievementBadgeViewProps } from './AchievementBadgeView.types';
|
||||||
|
|
||||||
|
export const AchievementBadgeView: FC<AchievementBadgeViewProps> = props =>
|
||||||
|
{
|
||||||
|
const { achievement = null, scale = 1, ...rest } = props;
|
||||||
|
|
||||||
|
if(!achievement) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BadgeImageView badgeCode={ AchievementUtilities.getBadgeCode(achievement) } isGrayscale={ !AchievementUtilities.hasStarted(achievement) } scale={ scale } { ...rest } />
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
import { AchievementData } from '@nitrots/nitro-renderer';
|
||||||
|
import { NitroLayoutBaseProps } from '../../../../layout/base';
|
||||||
|
|
||||||
|
export interface AchievementBadgeViewProps extends NitroLayoutBaseProps
|
||||||
|
{
|
||||||
|
achievement: AchievementData;
|
||||||
|
scale?: number;
|
||||||
|
}
|