mirror of
https://github.com/billsonnn/nitro-react.git
synced 2024-12-04 18:56:28 +01:00
Continue layout changes
This commit is contained in:
parent
6010103b90
commit
f5d64fa2b4
@ -1,10 +1,10 @@
|
|||||||
import { GetAssetManager, GetAvatarRenderManager, GetCommunication, GetConfiguration, GetLocalizationManager, GetRoomCameraWidgetManager, GetRoomEngine, GetRoomSessionManager, GetSessionDataManager, GetSoundManager, GetStage, GetTexturePool, GetTicker, HabboWebTools, LegacyExternalInterface, LoadGameUrlEvent, NitroLogger, NitroVersion, PrepareRenderer } from '@nitrots/nitro-renderer';
|
import { GetAssetManager, GetAvatarRenderManager, GetCommunication, GetConfiguration, GetLocalizationManager, GetRoomCameraWidgetManager, GetRoomEngine, GetRoomSessionManager, GetSessionDataManager, GetSoundManager, GetStage, GetTexturePool, GetTicker, HabboWebTools, LegacyExternalInterface, LoadGameUrlEvent, NitroLogger, NitroVersion, PrepareRenderer } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useEffect, useState } from 'react';
|
import { FC, useEffect, useState } from 'react';
|
||||||
import { GetUIVersion } from './api';
|
import { GetUIVersion } from './api';
|
||||||
import { classNames } from './common';
|
|
||||||
import { MainView } from './components/MainView';
|
import { MainView } from './components/MainView';
|
||||||
import { LoadingView } from './components/loading/LoadingView';
|
import { LoadingView } from './components/loading/LoadingView';
|
||||||
import { useMessageEvent } from './hooks';
|
import { useMessageEvent } from './hooks';
|
||||||
|
import { classNames } from './layout';
|
||||||
|
|
||||||
NitroVersion.UI_VERSION = GetUIVersion();
|
NitroVersion.UI_VERSION = GetUIVersion();
|
||||||
|
|
||||||
|
BIN
src/assets/images/ui/loading_icon.png
Normal file
BIN
src/assets/images/ui/loading_icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 164 B |
@ -1,4 +1,4 @@
|
|||||||
export * from '../layout/InfiniteGrid';
|
|
||||||
export * from './AutoGrid';
|
export * from './AutoGrid';
|
||||||
export * from './Base';
|
export * from './Base';
|
||||||
export * from './Button';
|
export * from './Button';
|
||||||
@ -13,7 +13,6 @@ export * from './Text';
|
|||||||
export * from './card';
|
export * from './card';
|
||||||
export * from './card/accordion';
|
export * from './card/accordion';
|
||||||
export * from './card/tabs';
|
export * from './card/tabs';
|
||||||
export * from './classNames';
|
|
||||||
export * from './draggable-window';
|
export * from './draggable-window';
|
||||||
export * from './layout';
|
export * from './layout';
|
||||||
export * from './layout/limited-edition';
|
export * from './layout/limited-edition';
|
||||||
|
@ -65,7 +65,7 @@ export const LayoutGridItem: FC<LayoutGridItemProps> = props =>
|
|||||||
{ (itemUniqueNumber > 0) &&
|
{ (itemUniqueNumber > 0) &&
|
||||||
<>
|
<>
|
||||||
<Base fit className="unique-bg-override" style={ { backgroundImage: `url(${ itemImage })` } } />
|
<Base fit className="unique-bg-override" style={ { backgroundImage: `url(${ itemImage })` } } />
|
||||||
<div className="position-absolute bottom-0 unique-item-counter">
|
<div className="absolute bottom-0 unique-item-counter">
|
||||||
<LayoutLimitedEditionStyledNumberView value={ itemUniqueNumber } />
|
<LayoutLimitedEditionStyledNumberView value={ itemUniqueNumber } />
|
||||||
</div>
|
</div>
|
||||||
</> }
|
</> }
|
||||||
|
@ -80,8 +80,8 @@ export const LayoutRoomPreviewerView: FC<LayoutRoomPreviewerViewProps> = props =
|
|||||||
}, [ roomPreviewer, elementRef, height ]);
|
}, [ roomPreviewer, elementRef, height ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="room-preview-container">
|
<div className="relative w-full">
|
||||||
<div ref={ elementRef } className="room-preview-image" style={ { height } } onClick={ onClick } />
|
<div ref={ elementRef } className="rounded-md shadow" style={ { height } } onClick={ onClick } />
|
||||||
{ children }
|
{ children }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -47,7 +47,7 @@ export const AchievementsView: FC<{}> = props =>
|
|||||||
<NitroCardView className="nitro-achievements" theme="primary-slim" uniqueKey="achievements">
|
<NitroCardView className="nitro-achievements" theme="primary-slim" uniqueKey="achievements">
|
||||||
<NitroCardHeaderView headerText={ LocalizeText('inventory.achievements') } onCloseClick={ event => setIsVisible(false) } />
|
<NitroCardHeaderView headerText={ LocalizeText('inventory.achievements') } onCloseClick={ event => setIsVisible(false) } />
|
||||||
{ selectedCategory &&
|
{ selectedCategory &&
|
||||||
<div className="position-relative gap-3 justify-center items-center cursor-pointer">
|
<div className="relative gap-3 justify-center items-center cursor-pointer">
|
||||||
<div className="nitro-achievements-back-arrow" onClick={ event => setSelectedCategoryCode(null) } />
|
<div className="nitro-achievements-back-arrow" onClick={ event => setSelectedCategoryCode(null) } />
|
||||||
<Column className="flex-grow-1" gap={ 0 }>
|
<Column className="flex-grow-1" gap={ 0 }>
|
||||||
<Text className="text-small" fontSize={ 4 } fontWeight="bold">{ LocalizeText(`quests.${ selectedCategory.code }.name`) }</Text>
|
<Text className="text-small" fontSize={ 4 } fontWeight="bold">{ LocalizeText(`quests.${ selectedCategory.code }.name`) }</Text>
|
||||||
|
@ -27,7 +27,7 @@ export const AvatarEditorFigurePreviewView: FC<{}> = props =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col figure-preview-container overflow-hidden position-relative">
|
<div className="flex flex-col figure-preview-container overflow-hidden relative">
|
||||||
<LayoutAvatarImageView direction={ direction } figure={ getFigureString } scale={ 2 } />
|
<LayoutAvatarImageView direction={ direction } figure={ getFigureString } scale={ 2 } />
|
||||||
<AvatarEditorIcon className="avatar-spotlight" icon="spotlight" />
|
<AvatarEditorIcon className="avatar-spotlight" icon="spotlight" />
|
||||||
<div className="avatar-shadow" />
|
<div className="avatar-shadow" />
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { DetailedHTMLProps, HTMLAttributes, PropsWithChildren, forwardRef } from 'react';
|
import { DetailedHTMLProps, HTMLAttributes, PropsWithChildren, forwardRef } from 'react';
|
||||||
import { classNames } from '../../common';
|
import { classNames } from '../../layout';
|
||||||
|
|
||||||
type AvatarIconType = 'male' | 'female' | 'clear' | 'sellable' | string;
|
type AvatarIconType = 'male' | 'female' | 'clear' | 'sellable' | string;
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { GetAvatarRenderManager, IAvatarFigureContainer, SaveWardrobeOutfitMessageComposer } from '@nitrots/nitro-renderer';
|
import { GetAvatarRenderManager, IAvatarFigureContainer, SaveWardrobeOutfitMessageComposer } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useCallback } from 'react';
|
import { FC, useCallback } from 'react';
|
||||||
import { GetClubMemberLevel, GetConfigurationValue, LocalizeText, SendMessageComposer } from '../../api';
|
import { GetClubMemberLevel, GetConfigurationValue, LocalizeText, SendMessageComposer } from '../../api';
|
||||||
import { Button, InfiniteGrid, LayoutAvatarImageView, LayoutCurrencyIcon, LayoutGridItem } from '../../common';
|
import { Button, LayoutAvatarImageView, LayoutCurrencyIcon } from '../../common';
|
||||||
import { useAvatarEditor } from '../../hooks';
|
import { useAvatarEditor } from '../../hooks';
|
||||||
|
import { InfiniteGrid } from '../../layout';
|
||||||
|
|
||||||
export const AvatarEditorWardrobeView: FC<{}> = props =>
|
export const AvatarEditorWardrobeView: FC<{}> = props =>
|
||||||
{
|
{
|
||||||
@ -43,18 +44,18 @@ export const AvatarEditorWardrobeView: FC<{}> = props =>
|
|||||||
if(figureContainer) clubLevel = GetAvatarRenderManager().getFigureClubLevel(figureContainer, gender);
|
if(figureContainer) clubLevel = GetAvatarRenderManager().getFigureClubLevel(figureContainer, gender);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutGridItem className="nitro-avatar-editor-wardrobe-figure-preview" overflow="hidden" position="relative">
|
<InfiniteGrid.Item className="nitro-avatar-editor-wardrobe-figure-preview">
|
||||||
{ figureContainer &&
|
{ figureContainer &&
|
||||||
<LayoutAvatarImageView direction={ 2 } figure={ figureContainer.getFigureString() } gender={ gender } /> }
|
<LayoutAvatarImageView direction={ 2 } figure={ figureContainer.getFigureString() } gender={ gender } /> }
|
||||||
<div className="avatar-shadow" />
|
<div className="avatar-shadow" />
|
||||||
{ !hcDisabled && (clubLevel > 0) && <LayoutCurrencyIcon className="position-absolute top-1 start-1" type="hc" /> }
|
{ !hcDisabled && (clubLevel > 0) && <LayoutCurrencyIcon className="absolute top-1 start-1" type="hc" /> }
|
||||||
<div className="flex gap-1 button-container">
|
<div className="flex gap-1 button-container">
|
||||||
<Button fullWidth variant="link" onClick={ event => saveFigureAtWardrobeIndex(index) }>{ LocalizeText('avatareditor.wardrobe.save') }</Button>
|
<Button fullWidth variant="link" onClick={ event => saveFigureAtWardrobeIndex(index) }>{ LocalizeText('avatareditor.wardrobe.save') }</Button>
|
||||||
{ figureContainer &&
|
{ figureContainer &&
|
||||||
<Button fullWidth disabled={ (clubLevel > GetClubMemberLevel()) } variant="link" onClick={ event => wearFigureAtIndex(index) }>{ LocalizeText('widget.generic_usable.button.use') }</Button> }
|
<Button fullWidth disabled={ (clubLevel > GetClubMemberLevel()) } variant="link" onClick={ event => wearFigureAtIndex(index) }>{ LocalizeText('widget.generic_usable.button.use') }</Button> }
|
||||||
</div>
|
</div>
|
||||||
</LayoutGridItem>
|
</InfiniteGrid.Item>
|
||||||
)
|
)
|
||||||
} } overscan={ 5 } rows={ savedFigures } />
|
} } items={ savedFigures } overscan={ 5 } />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { AvatarFigurePartType } from '@nitrots/nitro-renderer';
|
import { AvatarFigurePartType } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useEffect, useState } from 'react';
|
import { FC, useEffect, useState } from 'react';
|
||||||
import { AvatarEditorThumbnailsHelper, GetConfigurationValue, IAvatarEditorCategoryPartItem } from '../../../api';
|
import { AvatarEditorThumbnailsHelper, GetConfigurationValue, IAvatarEditorCategoryPartItem } from '../../../api';
|
||||||
import { LayoutCurrencyIcon, LayoutGridItem, LayoutGridItemProps } from '../../../common';
|
import { LayoutCurrencyIcon, LayoutGridItemProps } from '../../../common';
|
||||||
import { useAvatarEditor } from '../../../hooks';
|
import { useAvatarEditor } from '../../../hooks';
|
||||||
|
import { InfiniteGrid } from '../../../layout';
|
||||||
import { AvatarEditorIcon } from '../AvatarEditorIcon';
|
import { AvatarEditorIcon } from '../AvatarEditorIcon';
|
||||||
|
|
||||||
export const AvatarEditorFigureSetItemView: FC<{
|
export const AvatarEditorFigureSetItemView: FC<{
|
||||||
@ -46,10 +47,10 @@ export const AvatarEditorFigureSetItemView: FC<{
|
|||||||
if(!partItem) return null;
|
if(!partItem) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutGridItem itemActive={ isSelected } itemImage={ (partItem.isClear ? undefined : assetUrl) } style={ { flex: '1', backgroundPosition: (setType === AvatarFigurePartType.HEAD) ? 'center -35px' : 'center' } } { ...rest }>
|
<InfiniteGrid.Item itemActive={ isSelected } itemImage={ (partItem.isClear ? undefined : assetUrl) } style={ { flex: '1', backgroundPosition: (setType === AvatarFigurePartType.HEAD) ? 'center -35px' : 'center' } } { ...rest }>
|
||||||
{ !partItem.isClear && isHC && <LayoutCurrencyIcon className="position-absolute end-1 bottom-1" type="hc" /> }
|
{ !partItem.isClear && isHC && <LayoutCurrencyIcon className="absolute end-1 bottom-1" type="hc" /> }
|
||||||
{ partItem.isClear && <AvatarEditorIcon icon="clear" /> }
|
{ partItem.isClear && <AvatarEditorIcon icon="clear" /> }
|
||||||
{ !partItem.isClear && partItem.partSet.isSellable && <AvatarEditorIcon className="end-1 bottom-1 position-absolute" icon="sellable" /> }
|
{ !partItem.isClear && partItem.partSet.isSellable && <AvatarEditorIcon className="end-1 bottom-1 absolute" icon="sellable" /> }
|
||||||
</LayoutGridItem>
|
</InfiniteGrid.Item>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import { IAvatarEditorCategory, IAvatarEditorCategoryPartItem } from '../../../api';
|
import { IAvatarEditorCategory, IAvatarEditorCategoryPartItem } from '../../../api';
|
||||||
import { InfiniteGrid } from '../../../common';
|
|
||||||
import { useAvatarEditor } from '../../../hooks';
|
import { useAvatarEditor } from '../../../hooks';
|
||||||
|
import { InfiniteGrid } from '../../../layout';
|
||||||
import { AvatarEditorFigureSetItemView } from './AvatarEditorFigureSetItemView';
|
import { AvatarEditorFigureSetItemView } from './AvatarEditorFigureSetItemView';
|
||||||
|
|
||||||
export const AvatarEditorFigureSetView: FC<{
|
export const AvatarEditorFigureSetView: FC<{
|
||||||
@ -29,13 +29,13 @@ export const AvatarEditorFigureSetView: FC<{
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InfiniteGrid columnCount={ columnCount } itemRender={ (item: IAvatarEditorCategoryPartItem) =>
|
<InfiniteGrid<IAvatarEditorCategoryPartItem> columnCount={ columnCount } itemRender={ (item: IAvatarEditorCategoryPartItem) =>
|
||||||
{
|
{
|
||||||
if(!item) return null;
|
if(!item) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AvatarEditorFigureSetItemView isSelected={ isPartItemSelected(item) } partItem={ item } setType={ category.setType } width={ `calc(100% / ${ columnCount }` } onClick={ event => selectEditorPart(category.setType, item.partSet?.id ?? -1) } />
|
<AvatarEditorFigureSetItemView isSelected={ isPartItemSelected(item) } partItem={ item } setType={ category.setType } width={ `calc(100% / ${ columnCount }` } onClick={ event => selectEditorPart(category.setType, item.partSet?.id ?? -1) } />
|
||||||
)
|
)
|
||||||
} } overscan={ columnCount } rows={ category.partItems } />
|
} } items={ category.partItems } overscan={ columnCount } />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { ColorConverter, IPartColor } from '@nitrots/nitro-renderer';
|
import { ColorConverter, IPartColor } from '@nitrots/nitro-renderer';
|
||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import { GetConfigurationValue } from '../../../api';
|
import { GetConfigurationValue } from '../../../api';
|
||||||
import { LayoutCurrencyIcon, LayoutGridItem, LayoutGridItemProps } from '../../../common';
|
import { LayoutCurrencyIcon, LayoutGridItemProps } from '../../../common';
|
||||||
|
import { InfiniteGrid } from '../../../layout';
|
||||||
|
|
||||||
export const AvatarEditorPaletteSetItem: FC<{
|
export const AvatarEditorPaletteSetItem: FC<{
|
||||||
setType: string;
|
setType: string;
|
||||||
@ -17,8 +18,8 @@ export const AvatarEditorPaletteSetItem: FC<{
|
|||||||
const isHC = !GetConfigurationValue<boolean>('hc.disabled', false) && (partColor.clubLevel > 0);
|
const isHC = !GetConfigurationValue<boolean>('hc.disabled', false) && (partColor.clubLevel > 0);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutGridItem itemHighlight className="clear-bg" itemActive={ isSelected } itemColor={ ColorConverter.int2rgb(partColor.rgb) } { ...rest }>
|
<InfiniteGrid.Item itemHighlight className="clear-bg" itemActive={ isSelected } itemColor={ ColorConverter.int2rgb(partColor.rgb) } { ...rest }>
|
||||||
{ isHC && <LayoutCurrencyIcon className="position-absolute end-1 bottom-1" type="hc" /> }
|
{ isHC && <LayoutCurrencyIcon className="absolute end-1 bottom-1" type="hc" /> }
|
||||||
</LayoutGridItem>
|
</InfiniteGrid.Item>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { IPartColor } from '@nitrots/nitro-renderer';
|
import { IPartColor } from '@nitrots/nitro-renderer';
|
||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import { IAvatarEditorCategory } from '../../../api';
|
import { IAvatarEditorCategory } from '../../../api';
|
||||||
import { InfiniteGrid } from '../../../common';
|
|
||||||
import { useAvatarEditor } from '../../../hooks';
|
import { useAvatarEditor } from '../../../hooks';
|
||||||
|
import { InfiniteGrid } from '../../../layout';
|
||||||
import { AvatarEditorPaletteSetItem } from './AvatarEditorPaletteSetItemView';
|
import { AvatarEditorPaletteSetItem } from './AvatarEditorPaletteSetItemView';
|
||||||
|
|
||||||
export const AvatarEditorPaletteSetView: FC<{
|
export const AvatarEditorPaletteSetView: FC<{
|
||||||
@ -24,13 +24,13 @@ export const AvatarEditorPaletteSetView: FC<{
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InfiniteGrid columnCount={ columnCount } itemRender={ (item: IPartColor) =>
|
<InfiniteGrid<IPartColor> columnCount={ columnCount } itemRender={ (item: IPartColor) =>
|
||||||
{
|
{
|
||||||
if(!item) return null;
|
if(!item) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AvatarEditorPaletteSetItem isSelected={ isPartColorSelected(item) } partColor={ item } setType={ category.setType } width={ `calc(100% / ${ columnCount }` } onClick={ event => selectEditorColor(category.setType, paletteIndex, item.id) } />
|
<AvatarEditorPaletteSetItem isSelected={ isPartColorSelected(item) } partColor={ item } setType={ category.setType } width={ `calc(100% / ${ columnCount }` } onClick={ event => selectEditorColor(category.setType, paletteIndex, item.id) } />
|
||||||
)
|
)
|
||||||
} } overscan={ columnCount } rows={ category.colorItems[paletteIndex] } />
|
} } items={ category.colorItems[paletteIndex] } overscan={ columnCount } />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -62,13 +62,13 @@ export const CameraWidgetCaptureView: FC<CameraWidgetCaptureViewProps> = props =
|
|||||||
<Column center className="nitro-camera-capture" gap={ 0 }>
|
<Column center className="nitro-camera-capture" gap={ 0 }>
|
||||||
{ selectedPicture && <img alt="" className="camera-area" src={ selectedPicture.imageUrl } /> }
|
{ selectedPicture && <img alt="" className="camera-area" src={ selectedPicture.imageUrl } /> }
|
||||||
<div className="camera-canvas drag-handler">
|
<div className="camera-canvas drag-handler">
|
||||||
<div className="position-absolute header-close" onClick={ onClose }>
|
<div className="absolute header-close" onClick={ onClose }>
|
||||||
<FaTimes className="fa-icon" />
|
<FaTimes className="fa-icon" />
|
||||||
</div>
|
</div>
|
||||||
{ !selectedPicture && <div ref={ elementRef } className="camera-area camera-view-finder" /> }
|
{ !selectedPicture && <div ref={ elementRef } className="camera-area camera-view-finder" /> }
|
||||||
{ selectedPicture &&
|
{ selectedPicture &&
|
||||||
<div className="camera-area camera-frame">
|
<div className="camera-area camera-frame">
|
||||||
<div className="camera-frame-preview-actions w-100 position-absolute bottom-0 py-2 text-center">
|
<div className="camera-frame-preview-actions w-100 absolute bottom-0 py-2 text-center">
|
||||||
<button className="btn btn-success me-3" title={ LocalizeText('camera.editor.button.tooltip') } onClick={ onEdit }>{ LocalizeText('camera.editor.button.text') }</button>
|
<button className="btn btn-success me-3" title={ LocalizeText('camera.editor.button.tooltip') } onClick={ onEdit }>{ LocalizeText('camera.editor.button.text') }</button>
|
||||||
<button className="btn btn-danger" onClick={ onDelete }>{ LocalizeText('camera.delete.button.text') }</button>
|
<button className="btn btn-danger" onClick={ onDelete }>{ LocalizeText('camera.delete.button.text') }</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,9 +2,10 @@ import { GetSessionDataManager, GiftReceiverNotFoundEvent, PurchaseFromCatalogAs
|
|||||||
import { ChangeEvent, FC, useCallback, useEffect, useMemo, useState } from 'react';
|
import { ChangeEvent, FC, useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { FaChevronLeft, FaChevronRight } from 'react-icons/fa';
|
import { FaChevronLeft, FaChevronRight } from 'react-icons/fa';
|
||||||
import { ColorUtils, LocalizeText, MessengerFriend, ProductTypeEnum, SendMessageComposer } from '../../../../api';
|
import { ColorUtils, LocalizeText, MessengerFriend, ProductTypeEnum, SendMessageComposer } from '../../../../api';
|
||||||
import { Button, Column, Flex, FormGroup, LayoutCurrencyIcon, LayoutFurniImageView, LayoutGiftTagView, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text, classNames } from '../../../../common';
|
import { Button, Column, Flex, FormGroup, LayoutCurrencyIcon, LayoutFurniImageView, LayoutGiftTagView, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common';
|
||||||
import { CatalogEvent, CatalogInitGiftEvent, CatalogPurchasedEvent } from '../../../../events';
|
import { CatalogEvent, CatalogInitGiftEvent, CatalogPurchasedEvent } from '../../../../events';
|
||||||
import { useCatalog, useFriends, useMessageEvent, useUiEvent } from '../../../../hooks';
|
import { useCatalog, useFriends, useMessageEvent, useUiEvent } from '../../../../hooks';
|
||||||
|
import { classNames } from '../../../../layout';
|
||||||
|
|
||||||
export const CatalogGiftView: FC<{}> = props =>
|
export const CatalogGiftView: FC<{}> = props =>
|
||||||
{
|
{
|
||||||
@ -275,7 +276,7 @@ export const CatalogGiftView: FC<{}> = props =>
|
|||||||
{ colors.map(color => <Button key={ color.id } active={ (color.id === selectedColorId) } disabled={ !isColorable } style={ { backgroundColor: color.color } } variant="dark" onClick={ () => setSelectedColorId(color.id) } />) }
|
{ colors.map(color => <Button key={ color.id } active={ (color.id === selectedColorId) } disabled={ !isColorable } style={ { backgroundColor: color.color } } variant="dark" onClick={ () => setSelectedColorId(color.id) } />) }
|
||||||
</div>
|
</div>
|
||||||
</Column>
|
</Column>
|
||||||
<div className="flex justify-content-between items-center">
|
<div className="flex items-center justify-content-between">
|
||||||
<Button className="text-black" variant="link" onClick={ onClose }>
|
<Button className="text-black" variant="link" onClick={ onClose }>
|
||||||
{ LocalizeText('cancel') }
|
{ LocalizeText('cancel') }
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -35,7 +35,7 @@ export const CatalogLayoutBadgeDisplayView: FC<CatalogLayoutProps> = props =>
|
|||||||
</> }
|
</> }
|
||||||
{ currentOffer &&
|
{ currentOffer &&
|
||||||
<>
|
<>
|
||||||
<div className="position-relative overflow-hidden">
|
<div className="relative overflow-hidden">
|
||||||
<CatalogViewProductWidgetView />
|
<CatalogViewProductWidgetView />
|
||||||
</div>
|
</div>
|
||||||
<Column className="flex-grow-1" gap={ 1 }>
|
<Column className="flex-grow-1" gap={ 1 }>
|
||||||
|
@ -150,7 +150,7 @@ export const CatalogLayoutColorGroupingView : FC<CatalogLayoutColorGroupViewProp
|
|||||||
</> }
|
</> }
|
||||||
{ currentOffer &&
|
{ currentOffer &&
|
||||||
<>
|
<>
|
||||||
<div className="position-relative overflow-hidden">
|
<div className="relative overflow-hidden">
|
||||||
<CatalogViewProductWidgetView />
|
<CatalogViewProductWidgetView />
|
||||||
<CatalogAddOnBadgeWidgetView className="bg-muted rounded bottom-1 end-1" position="absolute" />
|
<CatalogAddOnBadgeWidgetView className="bg-muted rounded bottom-1 end-1" position="absolute" />
|
||||||
{ currentOffer.product.furnitureData.hasIndexedColor &&
|
{ currentOffer.product.furnitureData.hasIndexedColor &&
|
||||||
|
@ -27,7 +27,7 @@ export const CatalogLayouGuildCustomFurniView: FC<CatalogLayoutProps> = props =>
|
|||||||
</> }
|
</> }
|
||||||
{ currentOffer &&
|
{ currentOffer &&
|
||||||
<>
|
<>
|
||||||
<div className="position-relative overflow-hidden">
|
<div className="relative overflow-hidden">
|
||||||
<CatalogViewProductWidgetView />
|
<CatalogViewProductWidgetView />
|
||||||
<CatalogGuildBadgeWidgetView className="bottom-1 end-1" position="absolute" />
|
<CatalogGuildBadgeWidgetView className="bottom-1 end-1" position="absolute" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -30,7 +30,7 @@ export const CatalogLayoutSpacesView: FC<CatalogLayoutProps> = props =>
|
|||||||
</> }
|
</> }
|
||||||
{ currentOffer &&
|
{ currentOffer &&
|
||||||
<>
|
<>
|
||||||
<div className="position-relative overflow-hidden">
|
<div className="relative overflow-hidden">
|
||||||
<CatalogViewProductWidgetView />
|
<CatalogViewProductWidgetView />
|
||||||
</div>
|
</div>
|
||||||
<Column grow gap={ 1 }>
|
<Column grow gap={ 1 }>
|
||||||
|
@ -216,7 +216,7 @@ export const CatalogLayoutPetView: FC<CatalogLayoutProps> = props =>
|
|||||||
</> }
|
</> }
|
||||||
{ currentOffer &&
|
{ currentOffer &&
|
||||||
<>
|
<>
|
||||||
<div className="position-relative overflow-hidden">
|
<div className="relative overflow-hidden">
|
||||||
<CatalogViewProductWidgetView />
|
<CatalogViewProductWidgetView />
|
||||||
<CatalogAddOnBadgeWidgetView className="bg-muted rounded bottom-1 end-1" position="absolute" />
|
<CatalogAddOnBadgeWidgetView className="bg-muted rounded bottom-1 end-1" position="absolute" />
|
||||||
{ ((petIndex > -1) && (petIndex <= 7)) &&
|
{ ((petIndex > -1) && (petIndex <= 7)) &&
|
||||||
|
@ -45,7 +45,7 @@ export const OfferWindowView = (props: { offer: TargetedOfferData, setOpen: Disp
|
|||||||
|
|
||||||
return <NitroCardView className="nitro-targeted-offer" theme="primary-slim" uniqueKey="targeted-offer">
|
return <NitroCardView className="nitro-targeted-offer" theme="primary-slim" uniqueKey="targeted-offer">
|
||||||
<NitroCardHeaderView headerText={ LocalizeText(offer.title) } onCloseClick={ event => setOpen(false) } />
|
<NitroCardHeaderView headerText={ LocalizeText(offer.title) } onCloseClick={ event => setOpen(false) } />
|
||||||
<div className="container-fluid p-1 position-relative justify-center items-center cursor-pointer gap-3 bg-danger">
|
<div className="container-fluid p-1 relative justify-center items-center cursor-pointer gap-3 bg-danger">
|
||||||
{ LocalizeText('targeted.offer.timeleft',[ 'timeleft' ],[ expirationTime() ]) }
|
{ LocalizeText('targeted.offer.timeleft',[ 'timeleft' ],[ expirationTime() ]) }
|
||||||
</div>
|
</div>
|
||||||
<NitroCardContentView gap={ 1 }>
|
<NitroCardContentView gap={ 1 }>
|
||||||
@ -68,7 +68,7 @@ export const OfferWindowView = (props: { offer: TargetedOfferData, setOpen: Disp
|
|||||||
</Flex>
|
</Flex>
|
||||||
<div className="w-50 h-100" style={ { background: `url(${ GetConfigurationValue('image.library.url') + offer.imageUrl }) no-repeat center` } } />
|
<div className="w-50 h-100" style={ { background: `url(${ GetConfigurationValue('image.library.url') + offer.imageUrl }) no-repeat center` } } />
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex column alignItems="center" className="price-ray position-absolute" justifyContent="center">
|
<Flex column alignItems="center" className="price-ray absolute" justifyContent="center">
|
||||||
<Text>{ LocalizeText('targeted.offer.price.label') }</Text>
|
<Text>{ LocalizeText('targeted.offer.price.label') }</Text>
|
||||||
{ offer.priceInCredits > 0 &&
|
{ offer.priceInCredits > 0 &&
|
||||||
<div className="flex gap-1">
|
<div className="flex gap-1">
|
||||||
|
@ -34,7 +34,7 @@ export const FriendBarItemView: FC<{ friend: MessengerFriend }> = props =>
|
|||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
<div ref={ elementRef } className="btn btn-primary friend-bar-item friend-bar-search">
|
<div ref={ elementRef } className="btn btn-primary friend-bar-item friend-bar-search">
|
||||||
<div className="friend-bar-item-head position-absolute"/>
|
<div className="friend-bar-item-head absolute"/>
|
||||||
<div className="text-truncate">{ LocalizeText('friend.bar.find.title') }</div>
|
<div className="text-truncate">{ LocalizeText('friend.bar.find.title') }</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -42,7 +42,7 @@ export const FriendBarItemView: FC<{ friend: MessengerFriend }> = props =>
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={ elementRef } className={ 'btn btn-success friend-bar-item ' + (isVisible ? 'friend-bar-item-active' : '') } onClick={ event => setVisible(prevValue => !prevValue) }>
|
<div ref={ elementRef } className={ 'btn btn-success friend-bar-item ' + (isVisible ? 'friend-bar-item-active' : '') } onClick={ event => setVisible(prevValue => !prevValue) }>
|
||||||
<div className={ `friend-bar-item-head position-absolute ${ friend.id > 0 ? 'avatar': 'group' }` }>
|
<div className={ `friend-bar-item-head absolute ${ friend.id > 0 ? 'avatar': 'group' }` }>
|
||||||
{ (friend.id > 0) && <LayoutAvatarImageView direction={ 2 } figure={ friend.figure } headOnly={ true } /> }
|
{ (friend.id > 0) && <LayoutAvatarImageView direction={ 2 } figure={ friend.figure } headOnly={ true } /> }
|
||||||
{ (friend.id <= 0) && <LayoutBadgeImageView badgeCode={ friend.figure } isGroup={ true } /> }
|
{ (friend.id <= 0) && <LayoutBadgeImageView badgeCode={ friend.figure } isGroup={ true } /> }
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,8 +2,9 @@ import { AddLinkEventTracker, GetSessionDataManager, GroupAdminGiveComposer, Gro
|
|||||||
import { FC, useCallback, useEffect, useState } from 'react';
|
import { FC, useCallback, useEffect, useState } from 'react';
|
||||||
import { FaChevronLeft, FaChevronRight } from 'react-icons/fa';
|
import { FaChevronLeft, FaChevronRight } from 'react-icons/fa';
|
||||||
import { GetUserProfile, LocalizeText, SendMessageComposer } from '../../../api';
|
import { GetUserProfile, LocalizeText, SendMessageComposer } from '../../../api';
|
||||||
import { Button, classNames, Column, Flex, Grid, LayoutAvatarImageView, LayoutBadgeImageView, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../common';
|
import { Button, Column, Flex, Grid, LayoutAvatarImageView, LayoutBadgeImageView, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../common';
|
||||||
import { useMessageEvent, useNotification } from '../../../hooks';
|
import { useMessageEvent, useNotification } from '../../../hooks';
|
||||||
|
import { classNames } from '../../../layout';
|
||||||
|
|
||||||
export const GroupMembersView: FC<{}> = props =>
|
export const GroupMembersView: FC<{}> = props =>
|
||||||
{
|
{
|
||||||
@ -166,8 +167,8 @@ export const GroupMembersView: FC<{}> = props =>
|
|||||||
{ membersData.result.map((member, index) =>
|
{ membersData.result.map((member, index) =>
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
<Flex key={ index } alignItems="center" className="member-list-item bg-white rounded p-2" gap={ 2 } overflow="hidden">
|
<Flex key={ index } alignItems="center" className="p-2 bg-white rounded member-list-item" gap={ 2 } overflow="hidden">
|
||||||
<div className="avatar-head cursor-pointer" onClick={ () => GetUserProfile(member.id) }>
|
<div className="cursor-pointer avatar-head" onClick={ () => GetUserProfile(member.id) }>
|
||||||
<LayoutAvatarImageView direction={ 2 } figure={ member.figure } headOnly={ true } />
|
<LayoutAvatarImageView direction={ 2 } figure={ member.figure } headOnly={ true } />
|
||||||
</div>
|
</div>
|
||||||
<Column grow gap={ 1 }>
|
<Column grow gap={ 1 }>
|
||||||
@ -182,11 +183,11 @@ export const GroupMembersView: FC<{}> = props =>
|
|||||||
</div> }
|
</div> }
|
||||||
{ membersData.admin && (member.rank === GroupRank.REQUESTED) &&
|
{ membersData.admin && (member.rank === GroupRank.REQUESTED) &&
|
||||||
<Flex alignItems="center">
|
<Flex alignItems="center">
|
||||||
<div className="nitro-friends-spritesheet icon-accept cursor-pointer" title={ LocalizeText('group.members.accept') } onClick={ event => acceptMembership(member) } />
|
<div className="cursor-pointer nitro-friends-spritesheet icon-accept" title={ LocalizeText('group.members.accept') } onClick={ event => acceptMembership(member) } />
|
||||||
</Flex> }
|
</Flex> }
|
||||||
{ membersData.admin && (member.rank !== GroupRank.OWNER) && (member.id !== GetSessionDataManager().userId) &&
|
{ membersData.admin && (member.rank !== GroupRank.OWNER) && (member.id !== GetSessionDataManager().userId) &&
|
||||||
<Flex alignItems="center">
|
<Flex alignItems="center">
|
||||||
<div className="nitro-friends-spritesheet icon-deny cursor-pointer" title={ LocalizeText(member.rank === GroupRank.REQUESTED ? 'group.members.reject' : 'group.members.kick') } onClick={ event => removeMemberOrDeclineMembership(member) } />
|
<div className="cursor-pointer nitro-friends-spritesheet icon-deny" title={ LocalizeText(member.rank === GroupRank.REQUESTED ? 'group.members.reject' : 'group.members.kick') } onClick={ event => removeMemberOrDeclineMembership(member) } />
|
||||||
</Flex> }
|
</Flex> }
|
||||||
</div>
|
</div>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { GroupSaveColorsComposer } from '@nitrots/nitro-renderer';
|
import { GroupSaveColorsComposer } from '@nitrots/nitro-renderer';
|
||||||
import { Dispatch, FC, SetStateAction, useCallback, useEffect, useState } from 'react';
|
import { Dispatch, FC, SetStateAction, useCallback, useEffect, useState } from 'react';
|
||||||
import { IGroupData, LocalizeText, SendMessageComposer } from '../../../../api';
|
import { IGroupData, LocalizeText, SendMessageComposer } from '../../../../api';
|
||||||
import { AutoGrid, Column, Grid, Text, classNames } from '../../../../common';
|
import { AutoGrid, Column, Grid, Text } from '../../../../common';
|
||||||
import { useGroup } from '../../../../hooks';
|
import { useGroup } from '../../../../hooks';
|
||||||
|
import { classNames } from '../../../../layout';
|
||||||
|
|
||||||
interface GroupTabColorsViewProps
|
interface GroupTabColorsViewProps
|
||||||
{
|
{
|
||||||
@ -99,7 +100,7 @@ export const GroupTabColorsView: FC<GroupTabColorsViewProps> = props =>
|
|||||||
<Column gap={ 1 } size={ 2 }>
|
<Column gap={ 1 } size={ 2 }>
|
||||||
<Text bold>{ LocalizeText('group.edit.color.guild.color') }</Text>
|
<Text bold>{ LocalizeText('group.edit.color.guild.color') }</Text>
|
||||||
{ groupData.groupColors && (groupData.groupColors.length > 0) &&
|
{ groupData.groupColors && (groupData.groupColors.length > 0) &&
|
||||||
<div className="flex overflow-hidden rounded border">
|
<div className="flex overflow-hidden border rounded">
|
||||||
<div className="group-color-swatch" style={ { backgroundColor: '#' + getGroupColor(0) } } />
|
<div className="group-color-swatch" style={ { backgroundColor: '#' + getGroupColor(0) } } />
|
||||||
<div className="group-color-swatch" style={ { backgroundColor: '#' + getGroupColor(1) } } />
|
<div className="group-color-swatch" style={ { backgroundColor: '#' + getGroupColor(1) } } />
|
||||||
</div> }
|
</div> }
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { GetSessionDataManager, GuideSessionGetRequesterRoomMessageComposer, GuideSessionInviteRequesterMessageComposer, GuideSessionMessageMessageComposer, GuideSessionRequesterRoomMessageEvent, GuideSessionResolvedMessageComposer } from '@nitrots/nitro-renderer';
|
import { GetSessionDataManager, GuideSessionGetRequesterRoomMessageComposer, GuideSessionInviteRequesterMessageComposer, GuideSessionMessageMessageComposer, GuideSessionRequesterRoomMessageEvent, GuideSessionResolvedMessageComposer } from '@nitrots/nitro-renderer';
|
||||||
import { FC, KeyboardEvent, useCallback, useEffect, useRef, useState } from 'react';
|
import { FC, KeyboardEvent, useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { GuideToolMessageGroup, LocalizeText, SendMessageComposer, TryVisitRoom } from '../../../api';
|
import { GuideToolMessageGroup, LocalizeText, SendMessageComposer, TryVisitRoom } from '../../../api';
|
||||||
import { Button, Column, Flex, LayoutAvatarImageView, Text, classNames } from '../../../common';
|
import { Button, Column, Flex, LayoutAvatarImageView, Text } from '../../../common';
|
||||||
import { useMessageEvent } from '../../../hooks';
|
import { useMessageEvent } from '../../../hooks';
|
||||||
|
import { classNames } from '../../../layout';
|
||||||
|
|
||||||
interface GuideToolOngoingViewProps
|
interface GuideToolOngoingViewProps
|
||||||
{
|
{
|
||||||
@ -72,7 +73,7 @@ export const GuideToolOngoingView: FC<GuideToolOngoingViewProps> = props =>
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Column fullHeight>
|
<Column fullHeight>
|
||||||
<Flex alignItems="center" className="bg-muted p-2 rounded" gap={ 1 } justifyContent="between">
|
<Flex alignItems="center" className="p-2 rounded bg-muted" gap={ 1 } justifyContent="between">
|
||||||
{ isGuide &&
|
{ isGuide &&
|
||||||
<div className="btn-group">
|
<div className="btn-group">
|
||||||
<Button onClick={ visit }>{ LocalizeText('guide.help.request.guide.ongoing.visit.button') }</Button>
|
<Button onClick={ visit }>{ LocalizeText('guide.help.request.guide.ongoing.visit.button') }</Button>
|
||||||
@ -85,13 +86,13 @@ export const GuideToolOngoingView: FC<GuideToolOngoingViewProps> = props =>
|
|||||||
</Column> }
|
</Column> }
|
||||||
<Button disabled variant="danger">{ LocalizeText('guide.help.common.report.link') }</Button>
|
<Button disabled variant="danger">{ LocalizeText('guide.help.common.report.link') }</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Column className="bg-muted rounded chat-messages p-2" gap={ 1 } overflow="hidden">
|
<Column className="p-2 rounded bg-muted chat-messages" gap={ 1 } overflow="hidden">
|
||||||
<Column overflow="auto">
|
<Column overflow="auto">
|
||||||
{ messageGroups.map((group, index) =>
|
{ messageGroups.map((group, index) =>
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
<Flex key={ index } fullWidth gap={ 2 } justifyContent={ isOwnChat(group.userId) ? 'end' : 'start' }>
|
<Flex key={ index } fullWidth gap={ 2 } justifyContent={ isOwnChat(group.userId) ? 'end' : 'start' }>
|
||||||
<div className="message-avatar flex-shrink-0">
|
<div className="flex-shrink-0 message-avatar">
|
||||||
{ (!isOwnChat(group.userId)) &&
|
{ (!isOwnChat(group.userId)) &&
|
||||||
<LayoutAvatarImageView direction={ 2 } figure={ userFigure } /> }
|
<LayoutAvatarImageView direction={ 2 } figure={ userFigure } /> }
|
||||||
</div>
|
</div>
|
||||||
@ -103,7 +104,7 @@ export const GuideToolOngoingView: FC<GuideToolOngoingViewProps> = props =>
|
|||||||
{ group.messages.map((chat, index) => <div key={ index } className={ classNames(chat.roomId ? 'text-break text-underline' : 'text-break', 'chat.roomId' && 'cursor-pointer') } onClick={ () => chat.roomId ? TryVisitRoom(chat.roomId) : null }>{ chat.message }</div>) }
|
{ group.messages.map((chat, index) => <div key={ index } className={ classNames(chat.roomId ? 'text-break text-underline' : 'text-break', 'chat.roomId' && 'cursor-pointer') } onClick={ () => chat.roomId ? TryVisitRoom(chat.roomId) : null }>{ chat.message }</div>) }
|
||||||
</div>
|
</div>
|
||||||
{ (isOwnChat(group.userId)) &&
|
{ (isOwnChat(group.userId)) &&
|
||||||
<div className="message-avatar flex-shrink-0">
|
<div className="flex-shrink-0 message-avatar">
|
||||||
<LayoutAvatarImageView direction={ 4 } figure={ GetSessionDataManager().figure } />
|
<LayoutAvatarImageView direction={ 4 } figure={ GetSessionDataManager().figure } />
|
||||||
</div> }
|
</div> }
|
||||||
</Flex>
|
</Flex>
|
||||||
|
@ -140,7 +140,7 @@ export const HcCenterView: FC<{}> = props =>
|
|||||||
</Button>
|
</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
</div>
|
</div>
|
||||||
<div className="end-0 p-4 top-0 habbo-avatar position-absolute">
|
<div className="end-0 p-4 top-0 habbo-avatar absolute">
|
||||||
<LayoutAvatarImageView direction={ 4 } figure={ userFigure } scale={ 2 } />
|
<LayoutAvatarImageView direction={ 4 } figure={ userFigure } scale={ 2 } />
|
||||||
</div>
|
</div>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
@ -90,12 +90,12 @@ export const HotelView: FC<{}> = props =>
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="background position-absolute" style={ (background && background.length) ? { backgroundImage: `url(${ background })` } : {} } />
|
<div className="background absolute" style={ (background && background.length) ? { backgroundImage: `url(${ background })` } : {} } />
|
||||||
<div className="sun position-absolute" style={ (sun && sun.length) ? { backgroundImage: `url(${ sun })` } : {} } />
|
<div className="sun absolute" style={ (sun && sun.length) ? { backgroundImage: `url(${ sun })` } : {} } />
|
||||||
<div className="drape position-absolute" style={ (drape && drape.length) ? { backgroundImage: `url(${ drape })` } : {} } />
|
<div className="drape absolute" style={ (drape && drape.length) ? { backgroundImage: `url(${ drape })` } : {} } />
|
||||||
<div className="left position-absolute" style={ (left && left.length) ? { backgroundImage: `url(${ left })` } : {} } />
|
<div className="left absolute" style={ (left && left.length) ? { backgroundImage: `url(${ left })` } : {} } />
|
||||||
<div className="right-repeat position-absolute" style={ (rightRepeat && rightRepeat.length) ? { backgroundImage: `url(${ rightRepeat })` } : {} } />
|
<div className="right-repeat absolute" style={ (rightRepeat && rightRepeat.length) ? { backgroundImage: `url(${ rightRepeat })` } : {} } />
|
||||||
<div className="right position-absolute" style={ (right && right.length) ? { backgroundImage: `url(${ right })` } : {} } />
|
<div className="right absolute" style={ (right && right.length) ? { backgroundImage: `url(${ right })` } : {} } />
|
||||||
{ GetConfigurationValue('hotelview')['show.avatar'] && (
|
{ GetConfigurationValue('hotelview')['show.avatar'] && (
|
||||||
<div className="avatar-image">
|
<div className="avatar-image">
|
||||||
<LayoutAvatarImageView direction={ 2 } figure={ userFigure } />
|
<LayoutAvatarImageView direction={ 2 } figure={ userFigure } />
|
||||||
|
@ -33,9 +33,9 @@ export const BonusRareWidgetView: FC<BonusRareWidgetViewProps> = props =>
|
|||||||
return (
|
return (
|
||||||
<div className="bonus-rare widget flex">
|
<div className="bonus-rare widget flex">
|
||||||
{ productType }
|
{ productType }
|
||||||
<div className="bg-light-dark rounded overflow-hidden position-relative bonus-bar-container">
|
<div className="bg-light-dark rounded overflow-hidden relative bonus-bar-container">
|
||||||
<div className="flex justify-center items-center size-full position-absolute small top-0">{ (totalCoinsForBonus - coinsStillRequiredToBuy) + '/' + totalCoinsForBonus }</div>
|
<div className="flex justify-center items-center size-full absolute small top-0">{ (totalCoinsForBonus - coinsStillRequiredToBuy) + '/' + totalCoinsForBonus }</div>
|
||||||
<div className="small bg-info rounded position-absolute top-0 h-100" style={ { width: ((totalCoinsForBonus - coinsStillRequiredToBuy) / totalCoinsForBonus) * 100 + '%' } }></div>
|
<div className="small bg-info rounded absolute top-0 h-100" style={ { width: ((totalCoinsForBonus - coinsStillRequiredToBuy) / totalCoinsForBonus) * 100 + '%' } }></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { MouseEventType } from '@nitrots/nitro-renderer';
|
import { MouseEventType } from '@nitrots/nitro-renderer';
|
||||||
import { FC, MouseEvent, useState } from 'react';
|
import { FC, MouseEvent, useState } from 'react';
|
||||||
import { attemptItemPlacement, GroupItem } from '../../../../api';
|
import { GroupItem, attemptItemPlacement } from '../../../../api';
|
||||||
import { LayoutGridItem } from '../../../../common';
|
|
||||||
import { useInventoryFurni } from '../../../../hooks';
|
import { useInventoryFurni } from '../../../../hooks';
|
||||||
|
import { InfiniteGrid, classNames } from '../../../../layout';
|
||||||
|
|
||||||
export const InventoryFurnitureItemView: FC<{ groupItem: GroupItem }> = props =>
|
export const InventoryFurnitureItemView: FC<{ groupItem: GroupItem }> = props =>
|
||||||
{
|
{
|
||||||
@ -34,5 +34,5 @@ export const InventoryFurnitureItemView: FC<{ groupItem: GroupItem }> = props =>
|
|||||||
|
|
||||||
const count = groupItem.getUnlockedCount();
|
const count = groupItem.getUnlockedCount();
|
||||||
|
|
||||||
return <LayoutGridItem className={ !count ? 'opacity-0-5 ' : '' } itemActive={ (groupItem === selectedItem) } itemCount={ groupItem.getUnlockedCount() } itemImage={ groupItem.iconUrl } itemUniqueNumber={ groupItem.stuffData.uniqueNumber } itemUnseen={ groupItem.hasUnseenItems } onDoubleClick={ onMouseEvent } onMouseDown={ onMouseEvent } onMouseOut={ onMouseEvent } onMouseUp={ onMouseEvent } { ...rest } />;
|
return <InfiniteGrid.Item className={ classNames(!count && 'opacity-50') } itemActive={ (groupItem === selectedItem) } itemCount={ groupItem.getUnlockedCount() } itemImage={ groupItem.iconUrl } itemUniqueNumber={ groupItem.stuffData.uniqueNumber } itemUnseen={ groupItem.hasUnseenItems } onDoubleClick={ onMouseEvent } onMouseDown={ onMouseEvent } onMouseOut={ onMouseEvent } onMouseUp={ onMouseEvent } />
|
||||||
}
|
}
|
||||||
|
@ -112,11 +112,11 @@ export const InventoryFurnitureView: FC<InventoryFurnitureViewProps> = props =>
|
|||||||
if(!groupItems || !groupItems.length) return <InventoryCategoryEmptyView desc={ LocalizeText('inventory.empty.desc') } title={ LocalizeText('inventory.empty.title') } />;
|
if(!groupItems || !groupItems.length) return <InventoryCategoryEmptyView desc={ LocalizeText('inventory.empty.desc') } title={ LocalizeText('inventory.empty.title') } />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="grid grid-cols-12 gap-2">
|
<div className="grid h-full grid-cols-12 gap-2 overflow-hidden">
|
||||||
<div className="flex flex-col col-span-7 overflow-hidden">
|
<div className="flex flex-col col-span-7 gap-1 overflow-hidden">
|
||||||
<InventoryFurnitureSearchView groupItems={ groupItems } setGroupItems={ setFilteredGroupItems } />
|
<InventoryFurnitureSearchView groupItems={ groupItems } setGroupItems={ setFilteredGroupItems } />
|
||||||
<InfiniteGrid<GroupItem>
|
<InfiniteGrid<GroupItem>
|
||||||
columnCount={ 5 }
|
columnCount={ 6 }
|
||||||
itemRender={ item => <InventoryFurnitureItemView groupItem={ item } /> }
|
itemRender={ item => <InventoryFurnitureItemView groupItem={ item } /> }
|
||||||
items={ filteredGroupItems } />
|
items={ filteredGroupItems } />
|
||||||
</div>
|
</div>
|
||||||
|
@ -123,17 +123,17 @@ export const ModToolsView: FC<{}> = props =>
|
|||||||
<NitroCardView className="nitro-mod-tools" theme="primary-slim" uniqueKey="mod-tools" windowPosition={ DraggableWindowPosition.TOP_LEFT } >
|
<NitroCardView className="nitro-mod-tools" theme="primary-slim" uniqueKey="mod-tools" windowPosition={ DraggableWindowPosition.TOP_LEFT } >
|
||||||
<NitroCardHeaderView headerText={ 'Mod Tools' } onCloseClick={ event => setIsVisible(false) } />
|
<NitroCardHeaderView headerText={ 'Mod Tools' } onCloseClick={ event => setIsVisible(false) } />
|
||||||
<NitroCardContentView className="text-black" gap={ 1 }>
|
<NitroCardContentView className="text-black" gap={ 1 }>
|
||||||
<Button className="position-relative" disabled={ (currentRoomId <= 0) } gap={ 1 } onClick={ event => CreateLinkEvent(`mod-tools/toggle-room-info/${ currentRoomId }`) }>
|
<Button className="relative" disabled={ (currentRoomId <= 0) } gap={ 1 } onClick={ event => CreateLinkEvent(`mod-tools/toggle-room-info/${ currentRoomId }`) }>
|
||||||
<div className="icon icon-small-room position-absolute start-1"/> Room Tool
|
<div className="icon icon-small-room absolute start-1"/> Room Tool
|
||||||
</Button>
|
</Button>
|
||||||
<Button className="position-relative" disabled={ (currentRoomId <= 0) } gap={ 1 } innerRef={ elementRef } onClick={ event => CreateLinkEvent(`mod-tools/toggle-room-chatlog/${ currentRoomId }`) }>
|
<Button className="relative" disabled={ (currentRoomId <= 0) } gap={ 1 } innerRef={ elementRef } onClick={ event => CreateLinkEvent(`mod-tools/toggle-room-chatlog/${ currentRoomId }`) }>
|
||||||
<div className="icon icon-chat-history position-absolute start-1"/> Chatlog Tool
|
<div className="icon icon-chat-history absolute start-1"/> Chatlog Tool
|
||||||
</Button>
|
</Button>
|
||||||
<Button className="position-relative" disabled={ !selectedUser } gap={ 1 } onClick={ () => CreateLinkEvent(`mod-tools/toggle-user-info/${ selectedUser.userId }`) }>
|
<Button className="relative" disabled={ !selectedUser } gap={ 1 } onClick={ () => CreateLinkEvent(`mod-tools/toggle-user-info/${ selectedUser.userId }`) }>
|
||||||
<div className="icon icon-user position-absolute start-1"/> User: { selectedUser ? selectedUser.username : '' }
|
<div className="icon icon-user absolute start-1"/> User: { selectedUser ? selectedUser.username : '' }
|
||||||
</Button>
|
</Button>
|
||||||
<Button className="position-relative" gap={ 1 } onClick={ () => setIsTicketsVisible(prevValue => !prevValue) }>
|
<Button className="relative" gap={ 1 } onClick={ () => setIsTicketsVisible(prevValue => !prevValue) }>
|
||||||
<div className="icon icon-tickets position-absolute start-1"/> Report Tool
|
<div className="icon icon-tickets absolute start-1"/> Report Tool
|
||||||
</Button>
|
</Button>
|
||||||
</NitroCardContentView>
|
</NitroCardContentView>
|
||||||
</NitroCardView> }
|
</NitroCardView> }
|
||||||
|
@ -2,9 +2,10 @@ import { CreateLinkEvent, GetCustomRoomFilterMessageComposer, GetSessionDataMana
|
|||||||
import { FC, useEffect, useState } from 'react';
|
import { FC, useEffect, useState } from 'react';
|
||||||
import { FaLink } from 'react-icons/fa';
|
import { FaLink } from 'react-icons/fa';
|
||||||
import { DispatchUiEvent, GetGroupInformation, LocalizeText, ReportType, SendMessageComposer } from '../../../api';
|
import { DispatchUiEvent, GetGroupInformation, LocalizeText, ReportType, SendMessageComposer } from '../../../api';
|
||||||
import { Button, Column, Flex, LayoutBadgeImageView, LayoutRoomThumbnailView, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text, UserProfileIconView, classNames } from '../../../common';
|
import { Button, Column, Flex, LayoutBadgeImageView, LayoutRoomThumbnailView, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text, UserProfileIconView } from '../../../common';
|
||||||
import { RoomWidgetThumbnailEvent } from '../../../events';
|
import { RoomWidgetThumbnailEvent } from '../../../events';
|
||||||
import { useHelp, useNavigator } from '../../../hooks';
|
import { useHelp, useNavigator } from '../../../hooks';
|
||||||
|
import { classNames } from '../../../layout';
|
||||||
|
|
||||||
export class NavigatorRoomInfoViewProps
|
export class NavigatorRoomInfoViewProps
|
||||||
{
|
{
|
||||||
@ -106,7 +107,7 @@ export const NavigatorRoomInfoView: FC<NavigatorRoomInfoViewProps> = props =>
|
|||||||
<>
|
<>
|
||||||
<Flex gap={ 2 } overflow="hidden">
|
<Flex gap={ 2 } overflow="hidden">
|
||||||
<LayoutRoomThumbnailView customUrl={ navigatorData.enteredGuestRoom.officialRoomPicRef } roomId={ navigatorData.enteredGuestRoom.roomId }>
|
<LayoutRoomThumbnailView customUrl={ navigatorData.enteredGuestRoom.officialRoomPicRef } roomId={ navigatorData.enteredGuestRoom.roomId }>
|
||||||
{ hasPermission('settings') && <i className="icon icon-camera-small position-absolute b-0 r-0 m-1 cursor-pointer top-0" onClick={ () => processAction('open_room_thumbnail_camera') } /> }
|
{ hasPermission('settings') && <i className="top-0 m-1 cursor-pointer icon icon-camera-small absolute b-0 r-0" onClick={ () => processAction('open_room_thumbnail_camera') } /> }
|
||||||
</LayoutRoomThumbnailView>
|
</LayoutRoomThumbnailView>
|
||||||
<Column grow gap={ 1 } overflow="hidden">
|
<Column grow gap={ 1 } overflow="hidden">
|
||||||
<div className="flex gap-1">
|
<div className="flex gap-1">
|
||||||
@ -131,13 +132,13 @@ export const NavigatorRoomInfoView: FC<NavigatorRoomInfoViewProps> = props =>
|
|||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
{ navigatorData.enteredGuestRoom.tags.map(tag =>
|
{ navigatorData.enteredGuestRoom.tags.map(tag =>
|
||||||
{
|
{
|
||||||
return <Text key={ tag } pointer className="bg-muted rounded p-1" onClick={ event => processAction('navigator_search_tag', tag) }>#{ tag }</Text>
|
return <Text key={ tag } pointer className="p-1 rounded bg-muted" onClick={ event => processAction('navigator_search_tag', tag) }>#{ tag }</Text>
|
||||||
}) }
|
}) }
|
||||||
</div> }
|
</div> }
|
||||||
</Column>
|
</Column>
|
||||||
<Column alignItems="center" gap={ 1 }>
|
<Column alignItems="center" gap={ 1 }>
|
||||||
{ hasPermission('settings') &&
|
{ hasPermission('settings') &&
|
||||||
<i className="icon icon-cog cursor-pointer" title={ LocalizeText('navigator.room.popup.info.room.settings') } onClick={ event => processAction('open_room_settings') } /> }
|
<i className="cursor-pointer icon icon-cog" title={ LocalizeText('navigator.room.popup.info.room.settings') } onClick={ event => processAction('open_room_settings') } /> }
|
||||||
<FaLink className="cursor-pointer fa-icon" title={ LocalizeText('navigator.embed.caption') } onClick={ event => CreateLinkEvent('navigator/toggle-room-link') } />
|
<FaLink className="cursor-pointer fa-icon" title={ LocalizeText('navigator.embed.caption') } onClick={ event => CreateLinkEvent('navigator/toggle-room-link') } />
|
||||||
</Column>
|
</Column>
|
||||||
</div>
|
</div>
|
||||||
|
@ -44,9 +44,9 @@ export const NavigatorSearchResultItemInfoView: FC<{
|
|||||||
<Flex gap={ 2 } overflow="hidden">
|
<Flex gap={ 2 } overflow="hidden">
|
||||||
<LayoutRoomThumbnailView className="flex flex-col items-center mb-1 justify-content-end" customUrl={ roomData.officialRoomPicRef } roomId={ roomData.roomId }>
|
<LayoutRoomThumbnailView className="flex flex-col items-center mb-1 justify-content-end" customUrl={ roomData.officialRoomPicRef } roomId={ roomData.roomId }>
|
||||||
{ roomData.habboGroupId > 0 && (
|
{ roomData.habboGroupId > 0 && (
|
||||||
<LayoutBadgeImageView badgeCode={ roomData.groupBadgeCode } className={ 'position-absolute top-0 start-0 m-1 ' } isGroup={ true }/>) }
|
<LayoutBadgeImageView badgeCode={ roomData.groupBadgeCode } className={ 'absolute top-0 start-0 m-1 ' } isGroup={ true }/>) }
|
||||||
{ roomData.doorMode !== RoomDataParser.OPEN_STATE && (
|
{ roomData.doorMode !== RoomDataParser.OPEN_STATE && (
|
||||||
<i className={ 'position-absolute end-0 mb-1 me-1 icon icon-navigator-room-' + (roomData.doorMode === RoomDataParser.DOORBELL_STATE ? 'locked' : roomData.doorMode === RoomDataParser.PASSWORD_STATE ? 'password' : roomData.doorMode === RoomDataParser.INVISIBLE_STATE ? 'invisible' : '') }/> ) }
|
<i className={ 'absolute end-0 mb-1 me-1 icon icon-navigator-room-' + (roomData.doorMode === RoomDataParser.DOORBELL_STATE ? 'locked' : roomData.doorMode === RoomDataParser.PASSWORD_STATE ? 'password' : roomData.doorMode === RoomDataParser.INVISIBLE_STATE ? 'invisible' : '') }/> ) }
|
||||||
</LayoutRoomThumbnailView>
|
</LayoutRoomThumbnailView>
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
<Text bold truncate className="flex-grow-1" style={ { maxHeight: 13 } }>
|
<Text bold truncate className="flex-grow-1" style={ { maxHeight: 13 } }>
|
||||||
@ -64,7 +64,7 @@ export const NavigatorSearchResultItemInfoView: FC<{
|
|||||||
<Text className="flex-grow-1">
|
<Text className="flex-grow-1">
|
||||||
{ roomData.description }
|
{ roomData.description }
|
||||||
</Text>
|
</Text>
|
||||||
<Flex className={ 'badge p-1 position-absolute m-1 bottom-0 end-0 m-2 ' + getUserCounterColor() } gap={ 1 }>
|
<Flex className={ 'badge p-1 absolute m-1 bottom-0 end-0 m-2 ' + getUserCounterColor() } gap={ 1 }>
|
||||||
<FaUser className="fa-icon" />
|
<FaUser className="fa-icon" />
|
||||||
{ roomData.userCount }
|
{ roomData.userCount }
|
||||||
</Flex>
|
</Flex>
|
||||||
|
@ -83,13 +83,13 @@ export const NavigatorSearchResultItemView: FC<NavigatorSearchResultItemViewProp
|
|||||||
if(thumbnail) return (
|
if(thumbnail) return (
|
||||||
<Column pointer alignItems="center" className="navigator-item p-1 bg-light rounded-3 small mb-1 flex-col border border-muted" gap={ 0 } overflow="hidden" onClick={ visitRoom } { ...rest }>
|
<Column pointer alignItems="center" className="navigator-item p-1 bg-light rounded-3 small mb-1 flex-col border border-muted" gap={ 0 } overflow="hidden" onClick={ visitRoom } { ...rest }>
|
||||||
<LayoutRoomThumbnailView className="flex flex-col items-center justify-content-end mb-1" customUrl={ roomData.officialRoomPicRef } roomId={ roomData.roomId }>
|
<LayoutRoomThumbnailView className="flex flex-col items-center justify-content-end mb-1" customUrl={ roomData.officialRoomPicRef } roomId={ roomData.roomId }>
|
||||||
{ roomData.habboGroupId > 0 && <LayoutBadgeImageView badgeCode={ roomData.groupBadgeCode } className={ 'position-absolute top-0 start-0 m-1' } isGroup={ true } /> }
|
{ roomData.habboGroupId > 0 && <LayoutBadgeImageView badgeCode={ roomData.groupBadgeCode } className={ 'absolute top-0 start-0 m-1' } isGroup={ true } /> }
|
||||||
<Flex center className={ 'badge p-1 position-absolute m-1 ' + getUserCounterColor() } gap={ 1 }>
|
<Flex center className={ 'badge p-1 absolute m-1 ' + getUserCounterColor() } gap={ 1 }>
|
||||||
<FaUser className="fa-icon" />
|
<FaUser className="fa-icon" />
|
||||||
{ roomData.userCount }
|
{ roomData.userCount }
|
||||||
</Flex>
|
</Flex>
|
||||||
{ (roomData.doorMode !== RoomDataParser.OPEN_STATE) &&
|
{ (roomData.doorMode !== RoomDataParser.OPEN_STATE) &&
|
||||||
<i className={ ('position-absolute end-0 mb-1 me-1 icon icon-navigator-room-' + ((roomData.doorMode === RoomDataParser.DOORBELL_STATE) ? 'locked' : (roomData.doorMode === RoomDataParser.PASSWORD_STATE) ? 'password' : (roomData.doorMode === RoomDataParser.INVISIBLE_STATE) ? 'invisible' : '')) } /> }
|
<i className={ ('absolute end-0 mb-1 me-1 icon icon-navigator-room-' + ((roomData.doorMode === RoomDataParser.DOORBELL_STATE) ? 'locked' : (roomData.doorMode === RoomDataParser.PASSWORD_STATE) ? 'password' : (roomData.doorMode === RoomDataParser.INVISIBLE_STATE) ? 'invisible' : '')) } /> }
|
||||||
</LayoutRoomThumbnailView>
|
</LayoutRoomThumbnailView>
|
||||||
<Flex className="w-100">
|
<Flex className="w-100">
|
||||||
<Text truncate className="flex-grow-1">{ roomData.roomName }</Text>
|
<Text truncate className="flex-grow-1">{ roomData.roomName }</Text>
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { GetRenderer } from '@nitrots/nitro-renderer';
|
import { GetRenderer } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useEffect, useRef } from 'react';
|
import { FC, useEffect, useRef } from 'react';
|
||||||
import { DispatchMouseEvent, DispatchTouchEvent } from '../../api';
|
import { DispatchMouseEvent, DispatchTouchEvent } from '../../api';
|
||||||
import { classNames } from '../../common';
|
|
||||||
import { useRoom } from '../../hooks';
|
import { useRoom } from '../../hooks';
|
||||||
|
import { classNames } from '../../layout';
|
||||||
import { RoomSpectatorView } from './spectator/RoomSpectatorView';
|
import { RoomSpectatorView } from './spectator/RoomSpectatorView';
|
||||||
import { RoomWidgetsView } from './widgets/RoomWidgetsView';
|
import { RoomWidgetsView } from './widgets/RoomWidgetsView';
|
||||||
|
|
||||||
|
@ -154,11 +154,13 @@ export const RoomWidgetsView: FC<{}> = props =>
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<div className="absolute top-0 left-0 pointer-events-none size-full">
|
||||||
|
<FurnitureWidgetsView />
|
||||||
|
</div>
|
||||||
<AvatarInfoWidgetView />
|
<AvatarInfoWidgetView />
|
||||||
<ChatWidgetView />
|
<ChatWidgetView />
|
||||||
<ChatInputView />
|
<ChatInputView />
|
||||||
<DoorbellWidgetView />
|
<DoorbellWidgetView />
|
||||||
<FurnitureWidgetsView />
|
|
||||||
<RoomToolsWidgetView />
|
<RoomToolsWidgetView />
|
||||||
<RoomFilterWordsWidgetView />
|
<RoomFilterWordsWidgetView />
|
||||||
<RoomThumbnailWidgetView />
|
<RoomThumbnailWidgetView />
|
||||||
|
@ -340,11 +340,11 @@ export const InfoStandWidgetFurniView: FC<InfoStandWidgetFurniViewProps> = props
|
|||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
<Flex gap={ 1 } position="relative">
|
<Flex gap={ 1 } position="relative">
|
||||||
{ avatarInfo.stuffData.isUnique &&
|
{ avatarInfo.stuffData.isUnique &&
|
||||||
<div className="position-absolute end-0">
|
<div className="absolute end-0">
|
||||||
<LayoutLimitedEditionCompactPlateView uniqueNumber={ avatarInfo.stuffData.uniqueNumber } uniqueSeries={ avatarInfo.stuffData.uniqueSeries } />
|
<LayoutLimitedEditionCompactPlateView uniqueNumber={ avatarInfo.stuffData.uniqueNumber } uniqueSeries={ avatarInfo.stuffData.uniqueSeries } />
|
||||||
</div> }
|
</div> }
|
||||||
{ (avatarInfo.stuffData.rarityLevel > -1) &&
|
{ (avatarInfo.stuffData.rarityLevel > -1) &&
|
||||||
<div className="position-absolute end-0">
|
<div className="absolute end-0">
|
||||||
<LayoutRarityLevelView level={ avatarInfo.stuffData.rarityLevel } />
|
<LayoutRarityLevelView level={ avatarInfo.stuffData.rarityLevel } />
|
||||||
</div> }
|
</div> }
|
||||||
<Flex center fullWidth>
|
<Flex center fullWidth>
|
||||||
|
@ -98,8 +98,8 @@ export const InfoStandWidgetPetView: FC<InfoStandWidgetPetViewProps> = props =>
|
|||||||
</Column> }
|
</Column> }
|
||||||
<Column alignItems="center" gap={ 1 }>
|
<Column alignItems="center" gap={ 1 }>
|
||||||
<Text small truncate variant="white">{ LocalizeText('infostand.pet.text.wellbeing') }</Text>
|
<Text small truncate variant="white">{ LocalizeText('infostand.pet.text.wellbeing') }</Text>
|
||||||
<div className="bg-light-dark rounded position-relative overflow-hidden w-100">
|
<div className="bg-light-dark rounded relative overflow-hidden w-100">
|
||||||
<div className="flex justify-center items-center size-full position-absolute">
|
<div className="flex justify-center items-center size-full absolute">
|
||||||
<Text small variant="white">{ avatarInfo.dead ? '00:00:00' : ConvertSeconds((remainingTimeToLive == 0 ? avatarInfo.remainingTimeToLive : remainingTimeToLive)).split(':')[1] + ':' + ConvertSeconds((remainingTimeToLive == null || remainingTimeToLive == undefined ? 0 : remainingTimeToLive)).split(':')[2] + ':' + ConvertSeconds((remainingTimeToLive == null || remainingTimeToLive == undefined ? 0 : remainingTimeToLive)).split(':')[3] }</Text>
|
<Text small variant="white">{ avatarInfo.dead ? '00:00:00' : ConvertSeconds((remainingTimeToLive == 0 ? avatarInfo.remainingTimeToLive : remainingTimeToLive)).split(':')[1] + ':' + ConvertSeconds((remainingTimeToLive == null || remainingTimeToLive == undefined ? 0 : remainingTimeToLive)).split(':')[2] + ':' + ConvertSeconds((remainingTimeToLive == null || remainingTimeToLive == undefined ? 0 : remainingTimeToLive)).split(':')[3] }</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-success rounded pet-stats" style={ { width: avatarInfo.dead ? '0' : Math.round((avatarInfo.maximumTimeToLive * 100) / (remainingTimeToLive)).toString() } } />
|
<div className="bg-success rounded pet-stats" style={ { width: avatarInfo.dead ? '0' : Math.round((avatarInfo.maximumTimeToLive * 100) / (remainingTimeToLive)).toString() } } />
|
||||||
@ -132,8 +132,8 @@ export const InfoStandWidgetPetView: FC<InfoStandWidgetPetViewProps> = props =>
|
|||||||
<Text center small wrap variant="white">{ LocalizeText('pet.level', [ 'level', 'maxlevel' ], [ avatarInfo.level.toString(), avatarInfo.maximumLevel.toString() ]) }</Text>
|
<Text center small wrap variant="white">{ LocalizeText('pet.level', [ 'level', 'maxlevel' ], [ avatarInfo.level.toString(), avatarInfo.maximumLevel.toString() ]) }</Text>
|
||||||
<Column alignItems="center" gap={ 1 }>
|
<Column alignItems="center" gap={ 1 }>
|
||||||
<Text small truncate variant="white">{ LocalizeText('infostand.pet.text.happiness') }</Text>
|
<Text small truncate variant="white">{ LocalizeText('infostand.pet.text.happiness') }</Text>
|
||||||
<div className="bg-light-dark rounded position-relative overflow-hidden w-100">
|
<div className="bg-light-dark rounded relative overflow-hidden w-100">
|
||||||
<div className="flex justify-center items-center size-full position-absolute">
|
<div className="flex justify-center items-center size-full absolute">
|
||||||
<Text small variant="white">{ avatarInfo.happyness + '/' + avatarInfo.maximumHappyness }</Text>
|
<Text small variant="white">{ avatarInfo.happyness + '/' + avatarInfo.maximumHappyness }</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-info rounded pet-stats" style={ { width: (avatarInfo.happyness / avatarInfo.maximumHappyness) * 100 + '%' } } />
|
<div className="bg-info rounded pet-stats" style={ { width: (avatarInfo.happyness / avatarInfo.maximumHappyness) * 100 + '%' } } />
|
||||||
@ -141,8 +141,8 @@ export const InfoStandWidgetPetView: FC<InfoStandWidgetPetViewProps> = props =>
|
|||||||
</Column>
|
</Column>
|
||||||
<Column alignItems="center" gap={ 1 }>
|
<Column alignItems="center" gap={ 1 }>
|
||||||
<Text small truncate variant="white">{ LocalizeText('infostand.pet.text.experience') }</Text>
|
<Text small truncate variant="white">{ LocalizeText('infostand.pet.text.experience') }</Text>
|
||||||
<div className="bg-light-dark rounded position-relative overflow-hidden w-100">
|
<div className="bg-light-dark rounded relative overflow-hidden w-100">
|
||||||
<div className="flex justify-center items-center size-full position-absolute">
|
<div className="flex justify-center items-center size-full absolute">
|
||||||
<Text small variant="white">{ avatarInfo.experience + '/' + avatarInfo.levelExperienceGoal }</Text>
|
<Text small variant="white">{ avatarInfo.experience + '/' + avatarInfo.levelExperienceGoal }</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-purple rounded pet-stats" style={ { width: (avatarInfo.experience / avatarInfo.levelExperienceGoal) * 100 + '%' } } />
|
<div className="bg-purple rounded pet-stats" style={ { width: (avatarInfo.experience / avatarInfo.levelExperienceGoal) * 100 + '%' } } />
|
||||||
@ -150,8 +150,8 @@ export const InfoStandWidgetPetView: FC<InfoStandWidgetPetViewProps> = props =>
|
|||||||
</Column>
|
</Column>
|
||||||
<Column alignItems="center" gap={ 1 }>
|
<Column alignItems="center" gap={ 1 }>
|
||||||
<Text small truncate variant="white">{ LocalizeText('infostand.pet.text.energy') }</Text>
|
<Text small truncate variant="white">{ LocalizeText('infostand.pet.text.energy') }</Text>
|
||||||
<div className="bg-light-dark rounded position-relative overflow-hidden w-100">
|
<div className="bg-light-dark rounded relative overflow-hidden w-100">
|
||||||
<div className="flex justify-center items-center size-full position-absolute">
|
<div className="flex justify-center items-center size-full absolute">
|
||||||
<Text small variant="white">{ avatarInfo.energy + '/' + avatarInfo.maximumEnergy }</Text>
|
<Text small variant="white">{ avatarInfo.energy + '/' + avatarInfo.maximumEnergy }</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-success rounded pet-stats" style={ { width: (avatarInfo.energy / avatarInfo.maximumEnergy) * 100 + '%' } } />
|
<div className="bg-success rounded pet-stats" style={ { width: (avatarInfo.energy / avatarInfo.maximumEnergy) * 100 + '%' } } />
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { GetSessionDataManager } from '@nitrots/nitro-renderer';
|
import { GetSessionDataManager } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useEffect, useMemo, useState } from 'react';
|
import { FC, useEffect, useMemo, useState } from 'react';
|
||||||
import { LocalizeText, RoomObjectItem } from '../../../../api';
|
import { LocalizeText, RoomObjectItem } from '../../../../api';
|
||||||
import { Flex, InfiniteScroll, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text, classNames } from '../../../../common';
|
import { Flex, InfiniteScroll, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common';
|
||||||
|
import { classNames } from '../../../../layout';
|
||||||
|
|
||||||
interface ChooserWidgetViewProps
|
interface ChooserWidgetViewProps
|
||||||
{
|
{
|
||||||
|
@ -94,7 +94,7 @@ export const ContextMenuView: FC<ContextMenuViewProps> = props =>
|
|||||||
|
|
||||||
const getClassNames = useMemo(() =>
|
const getClassNames = useMemo(() =>
|
||||||
{
|
{
|
||||||
const newClassNames: string[] = [ 'nitro-context-menu', 'position-absolute' ];
|
const newClassNames: string[] = [ 'nitro-context-menu', 'absolute' ];
|
||||||
|
|
||||||
if (isCollapsed) newClassNames.push('menu-hidden');
|
if (isCollapsed) newClassNames.push('menu-hidden');
|
||||||
|
|
||||||
|
@ -2,8 +2,9 @@ import { RoomEngineTriggerWidgetEvent } from '@nitrots/nitro-renderer';
|
|||||||
import { FC, useEffect, useMemo, useState } from 'react';
|
import { FC, useEffect, useMemo, useState } from 'react';
|
||||||
import ReactSlider from 'react-slider';
|
import ReactSlider from 'react-slider';
|
||||||
import { ColorUtils, FurnitureDimmerUtilities, GetConfigurationValue, LocalizeText } from '../../../../api';
|
import { ColorUtils, FurnitureDimmerUtilities, GetConfigurationValue, LocalizeText } from '../../../../api';
|
||||||
import { Button, Column, Grid, NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView, Text, classNames } from '../../../../common';
|
import { Button, Column, Grid, NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView, Text } from '../../../../common';
|
||||||
import { useFurnitureDimmerWidget, useNitroEvent } from '../../../../hooks';
|
import { useFurnitureDimmerWidget, useNitroEvent } from '../../../../hooks';
|
||||||
|
import { classNames } from '../../../../layout';
|
||||||
|
|
||||||
export const FurnitureDimmerView: FC<{}> = props =>
|
export const FurnitureDimmerView: FC<{}> = props =>
|
||||||
{
|
{
|
||||||
@ -41,7 +42,7 @@ export const FurnitureDimmerView: FC<{}> = props =>
|
|||||||
{ (dimmerState === 0) &&
|
{ (dimmerState === 0) &&
|
||||||
<Column alignItems="center">
|
<Column alignItems="center">
|
||||||
<div className="dimmer-banner" />
|
<div className="dimmer-banner" />
|
||||||
<Text center className="bg-muted rounded p-1">{ LocalizeText('widget.dimmer.info.off') }</Text>
|
<Text center className="p-1 rounded bg-muted">{ LocalizeText('widget.dimmer.info.off') }</Text>
|
||||||
<Button fullWidth variant="success" onClick={ () => FurnitureDimmerUtilities.changeState() }>{ LocalizeText('widget.dimmer.button.on') }</Button>
|
<Button fullWidth variant="success" onClick={ () => FurnitureDimmerUtilities.changeState() }>{ LocalizeText('widget.dimmer.button.on') }</Button>
|
||||||
</Column> }
|
</Column> }
|
||||||
{ (dimmerState === 1) &&
|
{ (dimmerState === 1) &&
|
||||||
|
@ -86,10 +86,10 @@ export const FurnitureMannequinView: FC<{}> = props =>
|
|||||||
<NitroCardContentView center>
|
<NitroCardContentView center>
|
||||||
<div className="flex w-100 gap-2 overflow-hidden">
|
<div className="flex w-100 gap-2 overflow-hidden">
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<div className="position-relative mannequin-preview">
|
<div className="relative mannequin-preview">
|
||||||
<LayoutAvatarImageView direction={ 2 } figure={ renderedFigure } position="absolute" />
|
<LayoutAvatarImageView direction={ 2 } figure={ renderedFigure } position="absolute" />
|
||||||
{ (clubLevel > 0) &&
|
{ (clubLevel > 0) &&
|
||||||
<LayoutCurrencyIcon className="position-absolute end-2 bottom-2" type="hc" /> }
|
<LayoutCurrencyIcon className="absolute end-2 bottom-2" type="hc" /> }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Column grow justifyContent="between" overflow="auto">
|
<Column grow justifyContent="between" overflow="auto">
|
||||||
|
@ -22,7 +22,7 @@ import { FurniturePlaylistEditorWidgetView } from './playlist-editor/FurniturePl
|
|||||||
export const FurnitureWidgetsView: FC<{}> = props =>
|
export const FurnitureWidgetsView: FC<{}> = props =>
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
<div className="position-absolute size-full nitro-room-widgets top-0 start-0">
|
<>
|
||||||
<FurnitureBackgroundColorView />
|
<FurnitureBackgroundColorView />
|
||||||
<FurnitureBadgeDisplayView />
|
<FurnitureBadgeDisplayView />
|
||||||
<FurnitureCraftingView />
|
<FurnitureCraftingView />
|
||||||
@ -42,6 +42,6 @@ export const FurnitureWidgetsView: FC<{}> = props =>
|
|||||||
<FurnitureTrophyView />
|
<FurnitureTrophyView />
|
||||||
<FurnitureContextMenuView />
|
<FurnitureContextMenuView />
|
||||||
<FurnitureYoutubeDisplayView />
|
<FurnitureYoutubeDisplayView />
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -16,10 +16,10 @@ export const FurniturePlaylistEditorWidgetView: FC<{}> = props =>
|
|||||||
<NitroCardHeaderView headerText={ LocalizeText('playlist.editor.title') } onCloseClick={ onClose } />
|
<NitroCardHeaderView headerText={ LocalizeText('playlist.editor.title') } onCloseClick={ onClose } />
|
||||||
<NitroCardContentView>
|
<NitroCardContentView>
|
||||||
<div className="flex flex-row gap-1 h-100">
|
<div className="flex flex-row gap-1 h-100">
|
||||||
<div className="w-50 position-relative overflow-hidden h-100 rounded flex flex-col">
|
<div className="w-50 relative overflow-hidden h-100 rounded flex flex-col">
|
||||||
<DiskInventoryView addToPlaylist={ addToPlaylist } diskInventory={ diskInventory } />
|
<DiskInventoryView addToPlaylist={ addToPlaylist } diskInventory={ diskInventory } />
|
||||||
</div>
|
</div>
|
||||||
<div className="w-50 position-relative overflow-hidden h-100 rounded flex flex-col">
|
<div className="w-50 relative overflow-hidden h-100 rounded flex flex-col">
|
||||||
<SongPlaylistView currentPlayingIndex={ currentPlayingIndex } furniId={ objectId } playlist={ playlist } removeFromPlaylist={ removeFromPlaylist } togglePlayPause={ togglePlayPause }/>
|
<SongPlaylistView currentPlayingIndex={ currentPlayingIndex } furniId={ objectId } playlist={ playlist } removeFromPlaylist={ removeFromPlaylist } togglePlayPause={ togglePlayPause }/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -57,5 +57,5 @@ export const ObjectLocationView: FC<ObjectLocationViewProps> = props =>
|
|||||||
}
|
}
|
||||||
}, [ objectId, category, noFollow ]);
|
}, [ objectId, category, noFollow ]);
|
||||||
|
|
||||||
return <div ref={ elementRef } className="object-location position-absolute" style={ { left: pos.x, top: pos.y, visibility: ((pos.x + (elementRef.current ? elementRef.current.offsetWidth : 0)) > -1) ? 'visible' : 'hidden' } } { ...rest } />;
|
return <div ref={ elementRef } className="object-location absolute" style={ { left: pos.x, top: pos.y, visibility: ((pos.x + (elementRef.current ? elementRef.current.offsetWidth : 0)) > -1) ? 'visible' : 'hidden' } } { ...rest } />;
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { UpdateRoomFilterMessageComposer } from '@nitrots/nitro-renderer';
|
import { UpdateRoomFilterMessageComposer } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useState } from 'react';
|
import { FC, useState } from 'react';
|
||||||
import { LocalizeText, SendMessageComposer } from '../../../../api';
|
import { LocalizeText, SendMessageComposer } from '../../../../api';
|
||||||
import { Button, Column, Flex, Grid, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text, classNames } from '../../../../common';
|
import { Button, Column, Flex, Grid, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common';
|
||||||
import { useFilterWordsWidget, useNavigator } from '../../../../hooks';
|
import { useFilterWordsWidget, useNavigator } from '../../../../hooks';
|
||||||
|
import { classNames } from '../../../../layout';
|
||||||
|
|
||||||
export const RoomFilterWordsWidgetView: FC<{}> = props =>
|
export const RoomFilterWordsWidgetView: FC<{}> = props =>
|
||||||
{
|
{
|
||||||
@ -51,7 +52,7 @@ export const RoomFilterWordsWidgetView: FC<{}> = props =>
|
|||||||
<NitroCardView className="nitro-guide-tool no-resize" theme="primary-slim">
|
<NitroCardView className="nitro-guide-tool no-resize" theme="primary-slim">
|
||||||
<NitroCardHeaderView headerText={ LocalizeText('navigator.roomsettings.roomfilter') } onCloseClick={ () => onClose() } />
|
<NitroCardHeaderView headerText={ LocalizeText('navigator.roomsettings.roomfilter') } onCloseClick={ () => onClose() } />
|
||||||
<NitroCardContentView className="text-black">
|
<NitroCardContentView className="text-black">
|
||||||
<Grid className="flex items-center justify-content-end gap-2">
|
<Grid className="flex items-center gap-2 justify-content-end">
|
||||||
<input className="form-control form-control-sm" maxLength={ 255 } type="text" value={ word } onChange={ event => onTyping(event.target.value) } />
|
<input className="form-control form-control-sm" maxLength={ 255 } type="text" value={ word } onChange={ event => onTyping(event.target.value) } />
|
||||||
<Button onClick={ () => processAction(true) }>{ LocalizeText('navigator.roomsettings.roomfilter.addword') }</Button>
|
<Button onClick={ () => processAction(true) }>{ LocalizeText('navigator.roomsettings.roomfilter.addword') }</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
@ -65,7 +66,7 @@ export const RoomFilterWordsWidgetView: FC<{}> = props =>
|
|||||||
)
|
)
|
||||||
}) }
|
}) }
|
||||||
</Column>
|
</Column>
|
||||||
<Grid className="flex items-center justify-content-end gap-2">
|
<Grid className="flex items-center gap-2 justify-content-end">
|
||||||
<Button disabled={ wordsFilter.length === 0 || !isSelectingWord } variant="danger" onClick={ () => processAction(false) }>{ LocalizeText('navigator.roomsettings.roomfilter.removeword') }</Button>
|
<Button disabled={ wordsFilter.length === 0 || !isSelectingWord } variant="danger" onClick={ () => processAction(false) }>{ LocalizeText('navigator.roomsettings.roomfilter.removeword') }</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
</NitroCardContentView>
|
</NitroCardContentView>
|
||||||
|
@ -18,8 +18,8 @@ export const RoomPromoteOtherEventWidgetView: FC<RoomPromoteOtherEventWidgetView
|
|||||||
</Flex>
|
</Flex>
|
||||||
<br /><br />
|
<br /><br />
|
||||||
<Column alignItems="center" gap={ 1 }>
|
<Column alignItems="center" gap={ 1 }>
|
||||||
<div className="bg-light-dark rounded position-relative overflow-hidden w-100">
|
<div className="bg-light-dark rounded relative overflow-hidden w-100">
|
||||||
<div className="flex justify-center items-center size-full position-absolute">
|
<div className="flex justify-center items-center size-full absolute">
|
||||||
<Text center variant="white">{ LocalizeText('navigator.eventinprogress') }</Text>
|
<Text center variant="white">{ LocalizeText('navigator.eventinprogress') }</Text>
|
||||||
</div>
|
</div>
|
||||||
<Text> </Text>
|
<Text> </Text>
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { CreateLinkEvent, GetGuestRoomResultEvent, GetRoomEngine, NavigatorSearchComposer, RateFlatMessageComposer } from '@nitrots/nitro-renderer';
|
import { CreateLinkEvent, GetGuestRoomResultEvent, GetRoomEngine, NavigatorSearchComposer, RateFlatMessageComposer } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useEffect, useState } from 'react';
|
import { FC, useEffect, useState } from 'react';
|
||||||
import { LocalizeText, SendMessageComposer } from '../../../../api';
|
import { LocalizeText, SendMessageComposer } from '../../../../api';
|
||||||
import { Text, TransitionAnimation, TransitionAnimationTypes, classNames } from '../../../../common';
|
import { Text, TransitionAnimation, TransitionAnimationTypes } from '../../../../common';
|
||||||
import { useMessageEvent, useNavigator, useRoom } from '../../../../hooks';
|
import { useMessageEvent, useNavigator, useRoom } from '../../../../hooks';
|
||||||
|
import { classNames } from '../../../../layout';
|
||||||
|
|
||||||
export const RoomToolsWidgetView: FC<{}> = props =>
|
export const RoomToolsWidgetView: FC<{}> = props =>
|
||||||
{
|
{
|
||||||
@ -72,24 +73,24 @@ export const RoomToolsWidgetView: FC<{}> = props =>
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex gap-2 nitro-room-tools-container">
|
<div className="flex gap-2 nitro-room-tools-container">
|
||||||
<div className="flex flex-col justify-center items-center nitro-room-tools p-2">
|
<div className="flex flex-col items-center justify-center p-2 nitro-room-tools">
|
||||||
<div className="icon icon-cog cursor-pointer" title={ LocalizeText('room.settings.button.text') } onClick={ () => handleToolClick('settings') } />
|
<div className="cursor-pointer icon icon-cog" title={ LocalizeText('room.settings.button.text') } onClick={ () => handleToolClick('settings') } />
|
||||||
<div className={ classNames('cursor-pointer', 'icon', (!isZoomedIn && 'icon-zoom-less'), (isZoomedIn && 'icon-zoom-more')) } title={ LocalizeText('room.zoom.button.text') } onClick={ () => handleToolClick('zoom') } />
|
<div className={ classNames('cursor-pointer', 'icon', (!isZoomedIn && 'icon-zoom-less'), (isZoomedIn && 'icon-zoom-more')) } title={ LocalizeText('room.zoom.button.text') } onClick={ () => handleToolClick('zoom') } />
|
||||||
<div className="icon icon-chat-history cursor-pointer" title={ LocalizeText('room.chathistory.button.text') } onClick={ () => handleToolClick('chat_history') } />
|
<div className="cursor-pointer icon icon-chat-history" title={ LocalizeText('room.chathistory.button.text') } onClick={ () => handleToolClick('chat_history') } />
|
||||||
{ navigatorData.canRate &&
|
{ navigatorData.canRate &&
|
||||||
<div className="icon icon-like-room cursor-pointer" title={ LocalizeText('room.like.button.text') } onClick={ () => handleToolClick('like_room') } /> }
|
<div className="cursor-pointer icon icon-like-room" title={ LocalizeText('room.like.button.text') } onClick={ () => handleToolClick('like_room') } /> }
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col justify-center">
|
<div className="flex flex-col justify-center">
|
||||||
<TransitionAnimation inProp={ isOpen } timeout={ 300 } type={ TransitionAnimationTypes.SLIDE_LEFT }>
|
<TransitionAnimation inProp={ isOpen } timeout={ 300 } type={ TransitionAnimationTypes.SLIDE_LEFT }>
|
||||||
<div className="flex flex-col justify-center items-center">
|
<div className="flex flex-col items-center justify-center">
|
||||||
<div className="flex flex-col nitro-room-tools-info rounded py-2 px-3">
|
<div className="flex flex-col px-3 py-2 rounded nitro-room-tools-info">
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
<Text wrap fontSize={ 4 } variant="white">{ roomName }</Text>
|
<Text wrap fontSize={ 4 } variant="white">{ roomName }</Text>
|
||||||
<Text fontSize={ 5 } variant="muted">{ roomOwner }</Text>
|
<Text fontSize={ 5 } variant="muted">{ roomOwner }</Text>
|
||||||
</div>
|
</div>
|
||||||
{ roomTags && roomTags.length > 0 &&
|
{ roomTags && roomTags.length > 0 &&
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
{ roomTags.map((tag, index) => <Text key={ index } pointer small className="rounded bg-primary p-1" variant="white" onClick={ () => handleToolClick('navigator_search_tag', tag) }>#{ tag }</Text>) }
|
{ roomTags.map((tag, index) => <Text key={ index } pointer small className="p-1 rounded bg-primary" variant="white" onClick={ () => handleToolClick('navigator_search_tag', tag) }>#{ tag }</Text>) }
|
||||||
</div> }
|
</div> }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { DetailedHTMLProps, forwardRef, HTMLAttributes, PropsWithChildren } from 'react';
|
import { DetailedHTMLProps, forwardRef, HTMLAttributes, PropsWithChildren } from 'react';
|
||||||
import { classNames } from '../../common';
|
import { classNames } from '../../layout';
|
||||||
|
|
||||||
export const ToolbarItemView = forwardRef<HTMLDivElement, PropsWithChildren<{
|
export const ToolbarItemView = forwardRef<HTMLDivElement, PropsWithChildren<{
|
||||||
icon: string;
|
icon: string;
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { CreateLinkEvent, Dispose, DropBounce, EaseOut, GetSessionDataManager, JumpBy, Motions, NitroToolbarAnimateIconEvent, PerkAllowancesMessageEvent, PerkEnum, Queue, Wait } from '@nitrots/nitro-renderer';
|
import { CreateLinkEvent, Dispose, DropBounce, EaseOut, GetSessionDataManager, JumpBy, Motions, NitroToolbarAnimateIconEvent, PerkAllowancesMessageEvent, PerkEnum, Queue, Wait } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useState } from 'react';
|
import { FC, useState } from 'react';
|
||||||
import { GetConfigurationValue, MessengerIconState, OpenMessengerChat, VisitDesktop } from '../../api';
|
import { GetConfigurationValue, MessengerIconState, OpenMessengerChat, VisitDesktop } from '../../api';
|
||||||
import { LayoutAvatarImageView, LayoutItemCountView, TransitionAnimation, TransitionAnimationTypes, classNames } from '../../common';
|
import { LayoutAvatarImageView, LayoutItemCountView, TransitionAnimation, TransitionAnimationTypes } from '../../common';
|
||||||
import { useAchievements, useFriends, useInventoryUnseenTracker, useMessageEvent, useMessenger, useNitroEvent, useSessionInfo } from '../../hooks';
|
import { useAchievements, useFriends, useInventoryUnseenTracker, useMessageEvent, useMessenger, useNitroEvent, useSessionInfo } from '../../hooks';
|
||||||
|
import { classNames } from '../../layout';
|
||||||
import { ToolbarItemView } from './ToolbarItemView';
|
import { ToolbarItemView } from './ToolbarItemView';
|
||||||
import { ToolbarMeView } from './ToolbarMeView';
|
import { ToolbarMeView } from './ToolbarMeView';
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ export const GroupsContainerView: FC<GroupsContainerViewProps> = props =>
|
|||||||
return (
|
return (
|
||||||
<LayoutGridItem key={ index } className="p-1" itemActive={ (selectedGroupId === group.groupId) } overflow="unset" onClick={ () => setSelectedGroupId(group.groupId) }>
|
<LayoutGridItem key={ index } className="p-1" itemActive={ (selectedGroupId === group.groupId) } overflow="unset" onClick={ () => setSelectedGroupId(group.groupId) }>
|
||||||
{ itsMe &&
|
{ itsMe &&
|
||||||
<i className={ 'position-absolute end-0 top-0 z-index-1 icon icon-group-' + (group.favourite ? 'favorite' : 'not-favorite') } onClick={ () => ToggleFavoriteGroup(group) } /> }
|
<i className={ 'absolute end-0 top-0 z-index-1 icon icon-group-' + (group.favourite ? 'favorite' : 'not-favorite') } onClick={ () => ToggleFavoriteGroup(group) } /> }
|
||||||
<LayoutBadgeImageView badgeCode={ group.badgeCode } isGroup={ true } />
|
<LayoutBadgeImageView badgeCode={ group.badgeCode } isGroup={ true } />
|
||||||
</LayoutGridItem>
|
</LayoutGridItem>
|
||||||
)
|
)
|
||||||
|
@ -2,8 +2,9 @@ import { AddLinkEventTracker, ILinkEventTracker, NitroSettingsEvent, RemoveLinkE
|
|||||||
import { FC, useEffect, useState } from 'react';
|
import { FC, useEffect, useState } from 'react';
|
||||||
import { FaVolumeDown, FaVolumeMute, FaVolumeUp } from 'react-icons/fa';
|
import { FaVolumeDown, FaVolumeMute, FaVolumeUp } from 'react-icons/fa';
|
||||||
import { DispatchMainEvent, DispatchUiEvent, LocalizeText, SendMessageComposer } from '../../api';
|
import { DispatchMainEvent, DispatchUiEvent, LocalizeText, SendMessageComposer } from '../../api';
|
||||||
import { NitroCardContentView, NitroCardHeaderView, NitroCardView, Text, classNames } from '../../common';
|
import { NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../common';
|
||||||
import { useCatalogPlaceMultipleItems, useCatalogSkipPurchaseConfirmation, useMessageEvent } from '../../hooks';
|
import { useCatalogPlaceMultipleItems, useCatalogSkipPurchaseConfirmation, useMessageEvent } from '../../hooks';
|
||||||
|
import { classNames } from '../../layout';
|
||||||
|
|
||||||
export const UserSettingsView: FC<{}> = props =>
|
export const UserSettingsView: FC<{}> = props =>
|
||||||
{
|
{
|
||||||
|
@ -22,12 +22,20 @@ body {
|
|||||||
width: 0.25rem;
|
width: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
@apply rounded-md;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
@apply rounded-md;
|
||||||
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar:horizontal {
|
::-webkit-scrollbar:horizontal {
|
||||||
height: 0.25rem;
|
@apply h-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar:not(:horizontal) {
|
::-webkit-scrollbar:not(:horizontal) {
|
||||||
width: 0.25rem;
|
@apply h-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar-track:horizontal {
|
::-webkit-scrollbar-track:horizontal {
|
||||||
@ -690,5 +698,14 @@ body {
|
|||||||
width: 18px;
|
width: 18px;
|
||||||
height: 19px;
|
height: 19px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.icon-loading {
|
||||||
|
background-image: url("@/assets/images/ui/loading_icon.png");
|
||||||
|
|
||||||
|
&.with-size {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import { useVirtualizer } from '@tanstack/react-virtual';
|
import { useVirtualizer } from '@tanstack/react-virtual';
|
||||||
import { Fragment, ReactElement, useEffect, useRef } from 'react';
|
import { DetailedHTMLProps, Fragment, HTMLAttributes, ReactElement, forwardRef, useEffect, useRef, useState } from 'react';
|
||||||
|
import { classNames } from './classNames';
|
||||||
|
import { styleNames } from './styleNames';
|
||||||
|
|
||||||
type Props<T> = {
|
type Props<T> = {
|
||||||
items: T[];
|
items: T[];
|
||||||
@ -9,7 +11,7 @@ type Props<T> = {
|
|||||||
itemRender?: (item: T, index?: number) => ReactElement;
|
itemRender?: (item: T, index?: number) => ReactElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const InfiniteGrid = <T,>(props: Props<T>) =>
|
const InfiniteGridRoot = <T,>(props: Props<T>) =>
|
||||||
{
|
{
|
||||||
const { items = [], columnCount = 4, overscan = 5, estimateSize = 45, itemRender = null } = props;
|
const { items = [], columnCount = 4, overscan = 5, estimateSize = 45, itemRender = null } = props;
|
||||||
const parentRef = useRef<HTMLDivElement>(null);
|
const parentRef = useRef<HTMLDivElement>(null);
|
||||||
@ -21,6 +23,29 @@ export const InfiniteGrid = <T,>(props: Props<T>) =>
|
|||||||
estimateSize: () => estimateSize
|
estimateSize: () => estimateSize
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
const element = parentRef.current;
|
||||||
|
|
||||||
|
if(!element || !items) return;
|
||||||
|
|
||||||
|
const checkAndApplyPadding = () =>
|
||||||
|
{
|
||||||
|
if(!element) return;
|
||||||
|
|
||||||
|
element.style.paddingRight = (element.scrollHeight > element.clientHeight) ? '0.25rem' : '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
checkAndApplyPadding();
|
||||||
|
|
||||||
|
window.addEventListener('resize', checkAndApplyPadding);
|
||||||
|
|
||||||
|
return () =>
|
||||||
|
{
|
||||||
|
window.removeEventListener('resize', checkAndApplyPadding);
|
||||||
|
}
|
||||||
|
}, [ items ]);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
if(!items || !items.length) return;
|
if(!items || !items.length) return;
|
||||||
@ -31,23 +56,22 @@ export const InfiniteGrid = <T,>(props: Props<T>) =>
|
|||||||
const virtualItems = virtualizer.getVirtualItems();
|
const virtualItems = virtualizer.getVirtualItems();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={ parentRef } className="size-full position-relative" style={ { overflowY: 'auto', height: virtualizer.getTotalSize() } }>
|
<div
|
||||||
|
ref={ parentRef }
|
||||||
|
className="overflow-y-auto size-full">
|
||||||
<div
|
<div
|
||||||
className="flex flex-col w-full gap-1"
|
className="flex flex-col w-full *:pb-1 relative"
|
||||||
style={ {
|
style={ {
|
||||||
transform: `translateY(${ virtualItems[0]?.start ?? 0 }px)`
|
height: virtualizer.getTotalSize()
|
||||||
} }>
|
} }>
|
||||||
{ virtualItems.map(virtualRow => (
|
{ virtualItems.map(virtualRow => (
|
||||||
<div
|
<div
|
||||||
key={ virtualRow.key + 'a' }
|
key={ virtualRow.key + 'a' }
|
||||||
ref={ virtualizer.measureElement }
|
ref={ virtualizer.measureElement }
|
||||||
className="grid grid-cols-12 gap-2 "
|
className={ `grid grid-cols-${ columnCount } gap-1 absolute top-0 left-0 h-[45px] last:pb-0 w-full` }
|
||||||
data-index={ virtualRow.index }
|
data-index={ virtualRow.index }
|
||||||
style={ {
|
style={ {
|
||||||
display: 'grid',
|
transform: `translateY(${ virtualRow.start }px)`
|
||||||
gap: '0.25rem',
|
|
||||||
minHeight: virtualRow.index === 0 ? estimateSize : virtualRow.size,
|
|
||||||
gridTemplateColumns: `repeat(${ columnCount }, 1fr)`
|
|
||||||
} }>
|
} }>
|
||||||
{ Array.from(Array(columnCount)).map((e,i) =>
|
{ Array.from(Array(columnCount)).map((e,i) =>
|
||||||
{
|
{
|
||||||
@ -68,3 +92,73 @@ export const InfiniteGrid = <T,>(props: Props<T>) =>
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const InfiniteGridItem = forwardRef<HTMLDivElement, {
|
||||||
|
itemImage?: string;
|
||||||
|
itemColor?: string;
|
||||||
|
itemActive?: boolean;
|
||||||
|
itemCount?: number;
|
||||||
|
itemCountMinimum?: number;
|
||||||
|
itemUniqueSoldout?: boolean;
|
||||||
|
itemUniqueNumber?: number;
|
||||||
|
itemUnseen?: boolean;
|
||||||
|
itemHighlight?: boolean;
|
||||||
|
disabled?: boolean;
|
||||||
|
} & DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>>((props, ref) =>
|
||||||
|
{
|
||||||
|
const { itemImage = undefined, itemColor = undefined, itemActive = false, itemCount = 1, itemCountMinimum = 1, itemUniqueSoldout = false, itemUniqueNumber = -2, itemUnseen = false, itemHighlight = false, disabled = false, className = null, style = {}, children = null, ...rest } = props;
|
||||||
|
const [ backgroundImageUrl, setBackgroundImageUrl ] = useState<string>(null);
|
||||||
|
const disposed = useRef<boolean>(false);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
if(!itemImage || !itemImage.length) return;
|
||||||
|
|
||||||
|
const image = new Image();
|
||||||
|
|
||||||
|
image.onload = () =>
|
||||||
|
{
|
||||||
|
if(disposed.current) return;
|
||||||
|
|
||||||
|
setBackgroundImageUrl(image.src);
|
||||||
|
}
|
||||||
|
|
||||||
|
image.src = itemImage;
|
||||||
|
}, [ itemImage ]);
|
||||||
|
|
||||||
|
useEffect(() =>
|
||||||
|
{
|
||||||
|
disposed.current = false;
|
||||||
|
|
||||||
|
return () =>
|
||||||
|
{
|
||||||
|
disposed.current = true;
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={ ref }
|
||||||
|
className={ classNames(
|
||||||
|
'flex flex-col items-center justify-center cursor-pointer overflow-hidden relative bg-center bg-no-repeat w-full rounded-md border-2',
|
||||||
|
(!backgroundImageUrl || !backgroundImageUrl.length) && 'nitro-icon icon-loading',
|
||||||
|
itemActive ? 'border-card-grid-item-active bg-card-grid-item-active' : 'border-card-grid-item-border bg-card-grid-item',
|
||||||
|
className
|
||||||
|
) }
|
||||||
|
style={ styleNames(
|
||||||
|
backgroundImageUrl && backgroundImageUrl.length && !(itemUniqueSoldout || (itemUniqueNumber > 0)) && {
|
||||||
|
backgroundImage: `url(${ backgroundImageUrl })`
|
||||||
|
},
|
||||||
|
style
|
||||||
|
) }
|
||||||
|
{ ...rest }>
|
||||||
|
{ children }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
InfiniteGridItem.displayName = 'InfiniteGridItem';
|
||||||
|
|
||||||
|
export const InfiniteGrid = Object.assign(InfiniteGridRoot, {
|
||||||
|
Item: InfiniteGridItem
|
||||||
|
});
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { DetailedHTMLProps, forwardRef, HTMLAttributes, MouseEvent, PropsWithChildren } from 'react';
|
import { DetailedHTMLProps, forwardRef, HTMLAttributes, MouseEvent, PropsWithChildren } from 'react';
|
||||||
import { classNames, DraggableWindow, DraggableWindowPosition, DraggableWindowProps } from '../common';
|
import { DraggableWindow, DraggableWindowPosition, DraggableWindowProps } from '../common';
|
||||||
|
import { classNames } from './classNames';
|
||||||
import { NitroItemCountBadge } from './NitroItemCountBadge';
|
import { NitroItemCountBadge } from './NitroItemCountBadge';
|
||||||
|
|
||||||
const NitroCardRoot = forwardRef<HTMLDivElement, PropsWithChildren<{
|
const NitroCardRoot = forwardRef<HTMLDivElement, PropsWithChildren<{
|
||||||
@ -57,7 +58,7 @@ const NitroCardContent = forwardRef<HTMLDivElement, {
|
|||||||
<div
|
<div
|
||||||
ref={ ref }
|
ref={ ref }
|
||||||
className={ classNames(
|
className={ classNames(
|
||||||
'overflow-auto bg-card-content-area p-2 h-full',
|
'flex flex-col overflow-auto bg-card-content-area p-2 h-full',
|
||||||
className
|
className
|
||||||
) }
|
) }
|
||||||
{ ...rest }>
|
{ ...rest }>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { DetailedHTMLProps, forwardRef, HTMLAttributes, PropsWithChildren } from 'react';
|
import { DetailedHTMLProps, forwardRef, HTMLAttributes, PropsWithChildren } from 'react';
|
||||||
import { classNames } from '../common';
|
import { classNames } from './classNames';
|
||||||
|
|
||||||
const classes = {
|
const classes = {
|
||||||
base: 'top-2 right-2 py-0.5 px-[3px] z-[1] rounded border',
|
base: 'top-2 right-2 py-0.5 px-[3px] z-[1] rounded border',
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
export * from './InfiniteGrid';
|
export * from './InfiniteGrid';
|
||||||
export * from './NitroCard';
|
export * from './NitroCard';
|
||||||
export * from './NitroItemCountBadge';
|
export * from './NitroItemCountBadge';
|
||||||
|
export * from './classNames';
|
||||||
|
export * from './styleNames';
|
||||||
|
8
src/layout/styleNames.ts
Normal file
8
src/layout/styleNames.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export const styleNames = (...styles: object[]) =>
|
||||||
|
{
|
||||||
|
let mergedStyle = {};
|
||||||
|
|
||||||
|
styles.filter(Boolean).forEach(style => mergedStyle = { ...mergedStyle, ...style });
|
||||||
|
|
||||||
|
return mergedStyle;
|
||||||
|
}
|
@ -10,7 +10,11 @@ const colors = {
|
|||||||
'card-border': '#283F5D',
|
'card-border': '#283F5D',
|
||||||
'card-tab-item': '#B6BEC5',
|
'card-tab-item': '#B6BEC5',
|
||||||
'card-tab-item-active': '#DFDFDF',
|
'card-tab-item-active': '#DFDFDF',
|
||||||
'card-content-area': '#DFDFDF'
|
'card-content-area': '#DFDFDF',
|
||||||
|
'card-grid-item': '#CDD3D9',
|
||||||
|
'card-grid-item-active': '#ECECEC',
|
||||||
|
'card-grid-item-border': '#B6BEC5',
|
||||||
|
'card-grid-item-border-active': '#FFFFFF',
|
||||||
};
|
};
|
||||||
|
|
||||||
const boxShadow = {
|
const boxShadow = {
|
||||||
@ -39,6 +43,20 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
safelist: [
|
||||||
|
'grid-cols-1',
|
||||||
|
'grid-cols-2',
|
||||||
|
'grid-cols-3',
|
||||||
|
'grid-cols-4',
|
||||||
|
'grid-cols-5',
|
||||||
|
'grid-cols-6',
|
||||||
|
'grid-cols-7',
|
||||||
|
'grid-cols-8',
|
||||||
|
'grid-cols-9',
|
||||||
|
'grid-cols-10',
|
||||||
|
'grid-cols-11',
|
||||||
|
'grid-cols-12'
|
||||||
|
],
|
||||||
darkMode: 'class',
|
darkMode: 'class',
|
||||||
plugins: [
|
plugins: [
|
||||||
require('@tailwindcss/forms'),
|
require('@tailwindcss/forms'),
|
||||||
|
Loading…
Reference in New Issue
Block a user