mirror of
https://github.com/billsonnn/nitro-react.git
synced 2025-01-18 13:26:27 +01:00
Continue inventory updates
This commit is contained in:
parent
4e848fd3f5
commit
69e90bd1d3
@ -1,16 +1,12 @@
|
||||
import { GetRenderer, GetTicker, NitroTicker, RoomPreviewer, TextureUtils } from '@nitrots/nitro-renderer';
|
||||
import { FC, MouseEvent, ReactNode, useEffect, useRef } from 'react';
|
||||
import { FC, MouseEvent, useEffect, useRef } from 'react';
|
||||
|
||||
export interface LayoutRoomPreviewerViewProps
|
||||
{
|
||||
export const LayoutRoomPreviewerView: FC<{
|
||||
roomPreviewer: RoomPreviewer;
|
||||
height?: number;
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
export const LayoutRoomPreviewerView: FC<LayoutRoomPreviewerViewProps> = props =>
|
||||
}> = props =>
|
||||
{
|
||||
const { roomPreviewer = null, height = 0, children = null } = props;
|
||||
const { roomPreviewer = null, height = 0 } = props;
|
||||
const elementRef = useRef<HTMLDivElement>();
|
||||
|
||||
const onClick = (event: MouseEvent<HTMLDivElement>) =>
|
||||
@ -80,9 +76,14 @@ export const LayoutRoomPreviewerView: FC<LayoutRoomPreviewerViewProps> = props =
|
||||
}, [ roomPreviewer, elementRef, height ]);
|
||||
|
||||
return (
|
||||
<div className="relative w-full">
|
||||
<div ref={ elementRef } className="rounded-md shadow" style={ { height } } onClick={ onClick } />
|
||||
{ children }
|
||||
</div>
|
||||
<div
|
||||
ref={ elementRef }
|
||||
className="relative w-full rounded-md shadow-room-previewer"
|
||||
style={ {
|
||||
height,
|
||||
minHeight: height,
|
||||
maxHeight: height
|
||||
} }
|
||||
onClick={ onClick } />
|
||||
);
|
||||
}
|
||||
|
@ -1,10 +1,13 @@
|
||||
import { GetEventDispatcher, NitroToolbarAnimateIconEvent, TextureUtils, ToolbarIconEnum } from '@nitrots/nitro-renderer';
|
||||
import { GetEventDispatcher, NitroToolbarAnimateIconEvent, RoomPreviewer, TextureUtils, ToolbarIconEnum } from '@nitrots/nitro-renderer';
|
||||
import { FC, useRef } from 'react';
|
||||
import { LayoutRoomPreviewerView, LayoutRoomPreviewerViewProps } from '../../../../common';
|
||||
import { LayoutRoomPreviewerView } from '../../../../common';
|
||||
import { CatalogPurchasedEvent } from '../../../../events';
|
||||
import { useUiEvent } from '../../../../hooks';
|
||||
|
||||
export const CatalogRoomPreviewerView: FC<LayoutRoomPreviewerViewProps> = props =>
|
||||
export const CatalogRoomPreviewerView: FC<{
|
||||
roomPreviewer: RoomPreviewer;
|
||||
height?: number;
|
||||
}> = props =>
|
||||
{
|
||||
const { roomPreviewer = null } = props;
|
||||
const elementRef = useRef<HTMLDivElement>(null);
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { FC, PropsWithChildren } from 'react';
|
||||
import { UnseenItemCategory } from '../../../../api';
|
||||
import { LayoutBadgeImageView, LayoutGridItem } from '../../../../common';
|
||||
import { LayoutBadgeImageView } from '../../../../common';
|
||||
import { useInventoryBadges, useInventoryUnseenTracker } from '../../../../hooks';
|
||||
import { InfiniteGrid } from '../../../../layout';
|
||||
|
||||
export const InventoryBadgeItemView: FC<PropsWithChildren<{ badgeCode: string }>> = props =>
|
||||
{
|
||||
@ -11,9 +12,9 @@ export const InventoryBadgeItemView: FC<PropsWithChildren<{ badgeCode: string }>
|
||||
const unseen = isUnseen(UnseenItemCategory.BADGE, getBadgeId(badgeCode));
|
||||
|
||||
return (
|
||||
<LayoutGridItem itemActive={ (selectedBadgeCode === badgeCode) } itemUnseen={ unseen } onDoubleClick={ event => toggleBadge(selectedBadgeCode) } onMouseDown={ event => setSelectedBadgeCode(badgeCode) } { ...rest }>
|
||||
<InfiniteGrid.Item itemActive={ (selectedBadgeCode === badgeCode) } itemUnseen={ unseen } onDoubleClick={ event => toggleBadge(selectedBadgeCode) } onMouseDown={ event => setSelectedBadgeCode(badgeCode) } { ...rest }>
|
||||
<LayoutBadgeImageView badgeCode={ badgeCode } />
|
||||
{ children }
|
||||
</LayoutGridItem>
|
||||
</InfiniteGrid.Item>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { LocalizeBadgeName, LocalizeText, UnseenItemCategory } from '../../../../api';
|
||||
import { AutoGrid, Button, Column, Grid, LayoutBadgeImageView, Text } from '../../../../common';
|
||||
import { LayoutBadgeImageView } from '../../../../common';
|
||||
import { useInventoryBadges, useInventoryUnseenTracker } from '../../../../hooks';
|
||||
import { InfiniteGrid, NitroButton } from '../../../../layout';
|
||||
import { InventoryBadgeItemView } from './InventoryBadgeItemView';
|
||||
|
||||
export const InventoryBadgeView: FC<{}> = props =>
|
||||
@ -34,33 +35,36 @@ export const InventoryBadgeView: FC<{}> = props =>
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Grid>
|
||||
<Column overflow="hidden" size={ 7 }>
|
||||
<AutoGrid columnCount={ 4 }>
|
||||
{ badgeCodes && (badgeCodes.length > 0) && badgeCodes.map((badgeCode, index) =>
|
||||
{
|
||||
if(isWearingBadge(badgeCode)) return null;
|
||||
|
||||
return <InventoryBadgeItemView key={ index } badgeCode={ badgeCode } />
|
||||
}) }
|
||||
</AutoGrid>
|
||||
</Column>
|
||||
<Column className="justify-content-between" overflow="auto" size={ 5 }>
|
||||
<Column gap={ 2 } overflow="hidden">
|
||||
<Text>{ LocalizeText('inventory.badges.activebadges') }</Text>
|
||||
<AutoGrid columnCount={ 3 }>
|
||||
{ activeBadgeCodes && (activeBadgeCodes.length > 0) && activeBadgeCodes.map((badgeCode, index) => <InventoryBadgeItemView key={ index } badgeCode={ badgeCode } />) }
|
||||
</AutoGrid>
|
||||
</Column>
|
||||
<div className="grid h-full grid-cols-12 gap-2">
|
||||
<div className="flex flex-col col-span-7 gap-1 overflow-hidden">
|
||||
<InfiniteGrid<string>
|
||||
columnCount={ 5 }
|
||||
estimateSize={ 50 }
|
||||
itemRender={ item => <InventoryBadgeItemView badgeCode={ item } /> }
|
||||
items={ badgeCodes.filter(code => !isWearingBadge(code)) } />
|
||||
</div>
|
||||
<div className="flex flex-col justify-between col-span-5 overflow-auto">
|
||||
<div className="flex flex-col gap-2 overflow-hidden">
|
||||
<span className="text-sm truncate grow">{ LocalizeText('inventory.badges.activebadges') }</span>
|
||||
<InfiniteGrid<string>
|
||||
columnCount={ 3 }
|
||||
estimateSize={ 50 }
|
||||
itemRender={ item => <InventoryBadgeItemView badgeCode={ item } /> }
|
||||
items={ activeBadgeCodes } />
|
||||
</div>
|
||||
{ !!selectedBadgeCode &&
|
||||
<Column grow gap={ 2 } justifyContent="end">
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="items-center gap-2">
|
||||
<LayoutBadgeImageView shrink badgeCode={ selectedBadgeCode } />
|
||||
<Text>{ LocalizeBadgeName(selectedBadgeCode) }</Text>
|
||||
<span className="text-sm truncate grow">{ LocalizeBadgeName(selectedBadgeCode) }</span>
|
||||
</div>
|
||||
<Button disabled={ !isWearingBadge(selectedBadgeCode) && !canWearBadges() } variant={ (isWearingBadge(selectedBadgeCode) ? 'danger' : 'success') } onClick={ event => toggleBadge(selectedBadgeCode) }>{ LocalizeText(isWearingBadge(selectedBadgeCode) ? 'inventory.badges.clearbadge' : 'inventory.badges.wearbadge') }</Button>
|
||||
</Column> }
|
||||
</Column>
|
||||
</Grid>
|
||||
<NitroButton
|
||||
disabled={ !isWearingBadge(selectedBadgeCode) && !canWearBadges() }
|
||||
onClick={ event => toggleBadge(selectedBadgeCode) }>
|
||||
{ LocalizeText(isWearingBadge(selectedBadgeCode) ? 'inventory.badges.clearbadge' : 'inventory.badges.wearbadge') }
|
||||
</NitroButton>
|
||||
</div> }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -1,10 +1,13 @@
|
||||
import { MouseEventType } from '@nitrots/nitro-renderer';
|
||||
import { FC, MouseEvent, PropsWithChildren, useState } from 'react';
|
||||
import { attemptBotPlacement, IBotItem, UnseenItemCategory } from '../../../../api';
|
||||
import { LayoutAvatarImageView, LayoutGridItem } from '../../../../common';
|
||||
import { IBotItem, UnseenItemCategory, attemptBotPlacement } from '../../../../api';
|
||||
import { LayoutAvatarImageView } from '../../../../common';
|
||||
import { useInventoryBots, useInventoryUnseenTracker } from '../../../../hooks';
|
||||
import { InfiniteGrid } from '../../../../layout';
|
||||
|
||||
export const InventoryBotItemView: FC<PropsWithChildren<{ botItem: IBotItem }>> = props =>
|
||||
export const InventoryBotItemView: FC<PropsWithChildren<{
|
||||
botItem: IBotItem
|
||||
}>> = props =>
|
||||
{
|
||||
const { botItem = null, children = null, ...rest } = props;
|
||||
const [ isMouseDown, setMouseDown ] = useState(false);
|
||||
@ -35,9 +38,9 @@ export const InventoryBotItemView: FC<PropsWithChildren<{ botItem: IBotItem }>>
|
||||
}
|
||||
|
||||
return (
|
||||
<LayoutGridItem itemActive={ (selectedBot === botItem) } itemUnseen={ unseen } onDoubleClick={ onMouseEvent } onMouseDown={ onMouseEvent } onMouseOut={ onMouseEvent } onMouseUp={ onMouseEvent } { ...rest }>
|
||||
<InfiniteGrid.Item itemActive={ (selectedBot === botItem) } itemUnseen={ unseen } onDoubleClick={ onMouseEvent } onMouseDown={ onMouseEvent } onMouseOut={ onMouseEvent } onMouseUp={ onMouseEvent } { ...rest } className="*:[background-position-y:-32px]">
|
||||
<LayoutAvatarImageView direction={ 3 } figure={ botItem.botData.figure } headOnly={ true } />
|
||||
{ children }
|
||||
</LayoutGridItem>
|
||||
</InfiniteGrid.Item>
|
||||
);
|
||||
}
|
||||
|
@ -1,18 +1,16 @@
|
||||
import { GetRoomEngine, IRoomSession, RoomObjectVariable, RoomPreviewer } from '@nitrots/nitro-renderer';
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { LocalizeText, UnseenItemCategory, attemptBotPlacement } from '../../../../api';
|
||||
import { AutoGrid, Button, Column, Grid, LayoutRoomPreviewerView, Text } from '../../../../common';
|
||||
import { IBotItem, LocalizeText, UnseenItemCategory, attemptBotPlacement } from '../../../../api';
|
||||
import { LayoutRoomPreviewerView } from '../../../../common';
|
||||
import { useInventoryBots, useInventoryUnseenTracker } from '../../../../hooks';
|
||||
import { InfiniteGrid, NitroButton } from '../../../../layout';
|
||||
import { InventoryCategoryEmptyView } from '../InventoryCategoryEmptyView';
|
||||
import { InventoryBotItemView } from './InventoryBotItemView';
|
||||
|
||||
interface InventoryBotViewProps
|
||||
{
|
||||
export const InventoryBotView: FC<{
|
||||
roomSession: IRoomSession;
|
||||
roomPreviewer: RoomPreviewer;
|
||||
}
|
||||
|
||||
export const InventoryBotView: FC<InventoryBotViewProps> = props =>
|
||||
}> = props =>
|
||||
{
|
||||
const { roomSession = null, roomPreviewer = null } = props;
|
||||
const [ isVisible, setIsVisible ] = useState(false);
|
||||
@ -67,25 +65,26 @@ export const InventoryBotView: FC<InventoryBotViewProps> = props =>
|
||||
if(!botItems || !botItems.length) return <InventoryCategoryEmptyView desc={ LocalizeText('inventory.empty.bots.desc') } title={ LocalizeText('inventory.empty.bots.title') } />;
|
||||
|
||||
return (
|
||||
<Grid>
|
||||
<Column overflow="hidden" size={ 7 }>
|
||||
<AutoGrid columnCount={ 5 }>
|
||||
{ botItems && (botItems.length > 0) && botItems.map(item => <InventoryBotItemView key={ item.botData.id } botItem={ item } />) }
|
||||
</AutoGrid>
|
||||
</Column>
|
||||
<Column overflow="auto" size={ 5 }>
|
||||
<Column overflow="hidden" position="relative">
|
||||
<div className="grid h-full grid-cols-12 gap-2">
|
||||
<div className="flex flex-col col-span-7 gap-1 overflow-hidden">
|
||||
<InfiniteGrid<IBotItem>
|
||||
columnCount={ 6 }
|
||||
itemRender={ item => <InventoryBotItemView botItem={ item } /> }
|
||||
items={ botItems } />
|
||||
</div>
|
||||
<div className="flex flex-col col-span-5">
|
||||
<div className="relative flex flex-col">
|
||||
<LayoutRoomPreviewerView height={ 140 } roomPreviewer={ roomPreviewer } />
|
||||
</Column>
|
||||
</div>
|
||||
{ selectedBot &&
|
||||
<Column grow gap={ 2 } justifyContent="between">
|
||||
<Text grow truncate>{ selectedBot.botData.name }</Text>
|
||||
<div className="flex flex-col justify-between gap-2 grow">
|
||||
<span className="truncate grow">{ selectedBot.botData.name }</span>
|
||||
{ !!roomSession &&
|
||||
<Button variant="success" onClick={ event => attemptBotPlacement(selectedBot) }>
|
||||
<NitroButton onClick={ event => attemptBotPlacement(selectedBot) }>
|
||||
{ LocalizeText('inventory.furni.placetoroom') }
|
||||
</Button> }
|
||||
</Column> }
|
||||
</Column>
|
||||
</Grid>
|
||||
</NitroButton> }
|
||||
</div> }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -4,7 +4,9 @@ import { GroupItem, attemptItemPlacement } from '../../../../api';
|
||||
import { useInventoryFurni } from '../../../../hooks';
|
||||
import { InfiniteGrid, classNames } from '../../../../layout';
|
||||
|
||||
export const InventoryFurnitureItemView: FC<{ groupItem: GroupItem }> = props =>
|
||||
export const InventoryFurnitureItemView: FC<{
|
||||
groupItem: GroupItem
|
||||
}> = props =>
|
||||
{
|
||||
const { groupItem = null, ...rest } = props;
|
||||
const [ isMouseDown, setMouseDown ] = useState(false);
|
||||
|
@ -1,15 +1,12 @@
|
||||
import { Dispatch, FC, SetStateAction, useEffect, useState } from 'react';
|
||||
import { FaSearch } from 'react-icons/fa';
|
||||
import { GroupItem, LocalizeText } from '../../../../api';
|
||||
import { Button } from '../../../../common';
|
||||
import { NitroButton, NitroInput } from '../../../../layout';
|
||||
|
||||
export interface InventoryFurnitureSearchViewProps
|
||||
{
|
||||
export const InventoryFurnitureSearchView: FC<{
|
||||
groupItems: GroupItem[];
|
||||
setGroupItems: Dispatch<SetStateAction<GroupItem[]>>;
|
||||
}
|
||||
|
||||
export const InventoryFurnitureSearchView: FC<InventoryFurnitureSearchViewProps> = props =>
|
||||
}> = props =>
|
||||
{
|
||||
const { groupItems = [], setGroupItems = null } = props;
|
||||
const [ searchValue, setSearchValue ] = useState('');
|
||||
@ -38,10 +35,13 @@ export const InventoryFurnitureSearchView: FC<InventoryFurnitureSearchViewProps>
|
||||
|
||||
return (
|
||||
<div className="flex gap-1">
|
||||
<input className="form-control form-control-sm" placeholder={ LocalizeText('generic.search') } type="text" value={ searchValue } onChange={ event => setSearchValue(event.target.value) } />
|
||||
<Button variant="primary">
|
||||
<NitroInput
|
||||
placeholder={ LocalizeText('generic.search') }
|
||||
value={ searchValue }
|
||||
onChange={ event => setSearchValue(event.target.value) } />
|
||||
<NitroButton>
|
||||
<FaSearch className="fa-icon" />
|
||||
</Button>
|
||||
</NitroButton>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -2,19 +2,14 @@ import { InfiniteGrid } from '@layout/InfiniteGrid';
|
||||
import { GetRoomEngine, GetSessionDataManager, IRoomSession, RoomObjectVariable, RoomPreviewer, Vector3d } from '@nitrots/nitro-renderer';
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { DispatchUiEvent, FurniCategory, GroupItem, LocalizeText, UnseenItemCategory, attemptItemPlacement } from '../../../../api';
|
||||
import { Button, LayoutLimitedEditionCompactPlateView, LayoutRarityLevelView, LayoutRoomPreviewerView } from '../../../../common';
|
||||
import { LayoutLimitedEditionCompactPlateView, LayoutRarityLevelView, LayoutRoomPreviewerView } from '../../../../common';
|
||||
import { CatalogPostMarketplaceOfferEvent } from '../../../../events';
|
||||
import { useInventoryFurni, useInventoryUnseenTracker } from '../../../../hooks';
|
||||
import { NitroButton } from '../../../../layout';
|
||||
import { InventoryCategoryEmptyView } from '../InventoryCategoryEmptyView';
|
||||
import { InventoryFurnitureItemView } from './InventoryFurnitureItemView';
|
||||
import { InventoryFurnitureSearchView } from './InventoryFurnitureSearchView';
|
||||
|
||||
interface InventoryFurnitureViewProps
|
||||
{
|
||||
roomSession: IRoomSession;
|
||||
roomPreviewer: RoomPreviewer;
|
||||
}
|
||||
|
||||
const attemptPlaceMarketplaceOffer = (groupItem: GroupItem) =>
|
||||
{
|
||||
const item = groupItem.getLastItem();
|
||||
@ -26,7 +21,10 @@ const attemptPlaceMarketplaceOffer = (groupItem: GroupItem) =>
|
||||
DispatchUiEvent(new CatalogPostMarketplaceOfferEvent(item));
|
||||
}
|
||||
|
||||
export const InventoryFurnitureView: FC<InventoryFurnitureViewProps> = props =>
|
||||
export const InventoryFurnitureView: FC<{
|
||||
roomSession: IRoomSession;
|
||||
roomPreviewer: RoomPreviewer;
|
||||
}> = props =>
|
||||
{
|
||||
const { roomSession = null, roomPreviewer = null } = props;
|
||||
const [ isVisible, setIsVisible ] = useState(false);
|
||||
@ -112,7 +110,7 @@ export const InventoryFurnitureView: FC<InventoryFurnitureViewProps> = props =>
|
||||
if(!groupItems || !groupItems.length) return <InventoryCategoryEmptyView desc={ LocalizeText('inventory.empty.desc') } title={ LocalizeText('inventory.empty.title') } />;
|
||||
|
||||
return (
|
||||
<div className="grid h-full grid-cols-12 gap-2 overflow-hidden">
|
||||
<div className="grid h-full grid-cols-12 gap-2">
|
||||
<div className="flex flex-col col-span-7 gap-1 overflow-hidden">
|
||||
<InventoryFurnitureSearchView groupItems={ groupItems } setGroupItems={ setFilteredGroupItems } />
|
||||
<InfiniteGrid<GroupItem>
|
||||
@ -120,8 +118,8 @@ export const InventoryFurnitureView: FC<InventoryFurnitureViewProps> = props =>
|
||||
itemRender={ item => <InventoryFurnitureItemView groupItem={ item } /> }
|
||||
items={ filteredGroupItems } />
|
||||
</div>
|
||||
<div className="flex flex-col col-span-5 overflow-hidden">
|
||||
<div className="relative flex flex-col overflow-hidden">
|
||||
<div className="flex flex-col col-span-5">
|
||||
<div className="relative flex flex-col">
|
||||
<LayoutRoomPreviewerView height={ 140 } roomPreviewer={ roomPreviewer } />
|
||||
{ selectedItem && selectedItem.stuffData.isUnique &&
|
||||
<LayoutLimitedEditionCompactPlateView className="top-2 end-2" position="absolute" uniqueNumber={ selectedItem.stuffData.uniqueNumber } uniqueSeries={ selectedItem.stuffData.uniqueSeries } /> }
|
||||
@ -130,16 +128,16 @@ export const InventoryFurnitureView: FC<InventoryFurnitureViewProps> = props =>
|
||||
</div>
|
||||
{ selectedItem &&
|
||||
<div className="flex flex-col justify-between gap-2 grow">
|
||||
<span className="truncate grow">{ selectedItem.name }</span>
|
||||
<span className="text-sm truncate grow">{ selectedItem.name }</span>
|
||||
<div className="flex flex-col gap-1">
|
||||
{ !!roomSession &&
|
||||
<Button variant="success" onClick={ event => attemptItemPlacement(selectedItem) }>
|
||||
<NitroButton onClick={ event => attemptItemPlacement(selectedItem) }>
|
||||
{ LocalizeText('inventory.furni.placetoroom') }
|
||||
</Button> }
|
||||
</NitroButton> }
|
||||
{ (selectedItem && selectedItem.isSellable) &&
|
||||
<Button onClick={ event => attemptPlaceMarketplaceOffer(selectedItem) }>
|
||||
<NitroButton onClick={ event => attemptPlaceMarketplaceOffer(selectedItem) }>
|
||||
{ LocalizeText('inventory.marketplace.sell') }
|
||||
</Button> }
|
||||
</NitroButton> }
|
||||
</div>
|
||||
</div> }
|
||||
</div>
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { MouseEventType } from '@nitrots/nitro-renderer';
|
||||
import { FC, MouseEvent, PropsWithChildren, useState } from 'react';
|
||||
import { attemptPetPlacement, IPetItem, UnseenItemCategory } from '../../../../api';
|
||||
import { LayoutGridItem, LayoutPetImageView } from '../../../../common';
|
||||
import { IPetItem, UnseenItemCategory, attemptPetPlacement } from '../../../../api';
|
||||
import { LayoutPetImageView } from '../../../../common';
|
||||
import { useInventoryPets, useInventoryUnseenTracker } from '../../../../hooks';
|
||||
import { InfiniteGrid } from '../../../../layout';
|
||||
|
||||
export const InventoryPetItemView: FC<PropsWithChildren<{ petItem: IPetItem }>> = props =>
|
||||
{
|
||||
@ -35,9 +36,9 @@ export const InventoryPetItemView: FC<PropsWithChildren<{ petItem: IPetItem }>>
|
||||
}
|
||||
|
||||
return (
|
||||
<LayoutGridItem itemActive={ (petItem === selectedPet) } itemUnseen={ unseen } onDoubleClick={ onMouseEvent } onMouseDown={ onMouseEvent } onMouseOut={ onMouseEvent } onMouseUp={ onMouseEvent } { ...rest }>
|
||||
<InfiniteGrid.Item itemActive={ (petItem === selectedPet) } itemUnseen={ unseen } onDoubleClick={ onMouseEvent } onMouseDown={ onMouseEvent } onMouseOut={ onMouseEvent } onMouseUp={ onMouseEvent } { ...rest }>
|
||||
<LayoutPetImageView direction={ 3 } figure={ petItem.petData.figureData.figuredata } headOnly={ true } />
|
||||
{ children }
|
||||
</LayoutGridItem>
|
||||
</InfiniteGrid.Item>
|
||||
);
|
||||
}
|
||||
|
@ -1,18 +1,16 @@
|
||||
import { GetRoomEngine, IRoomSession, RoomObjectVariable, RoomPreviewer } from '@nitrots/nitro-renderer';
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { LocalizeText, UnseenItemCategory, attemptPetPlacement } from '../../../../api';
|
||||
import { AutoGrid, Button, Column, Grid, LayoutRoomPreviewerView, Text } from '../../../../common';
|
||||
import { IPetItem, LocalizeText, UnseenItemCategory, attemptPetPlacement } from '../../../../api';
|
||||
import { LayoutRoomPreviewerView } from '../../../../common';
|
||||
import { useInventoryPets, useInventoryUnseenTracker } from '../../../../hooks';
|
||||
import { InfiniteGrid, NitroButton } from '../../../../layout';
|
||||
import { InventoryCategoryEmptyView } from '../InventoryCategoryEmptyView';
|
||||
import { InventoryPetItemView } from './InventoryPetItemView';
|
||||
|
||||
interface InventoryPetViewProps
|
||||
{
|
||||
export const InventoryPetView: FC<{
|
||||
roomSession: IRoomSession;
|
||||
roomPreviewer: RoomPreviewer;
|
||||
}
|
||||
|
||||
export const InventoryPetView: FC<InventoryPetViewProps> = props =>
|
||||
}> = props =>
|
||||
{
|
||||
const { roomSession = null, roomPreviewer = null } = props;
|
||||
const [ isVisible, setIsVisible ] = useState(false);
|
||||
@ -66,25 +64,26 @@ export const InventoryPetView: FC<InventoryPetViewProps> = props =>
|
||||
if(!petItems || !petItems.length) return <InventoryCategoryEmptyView desc={ LocalizeText('inventory.empty.pets.desc') } title={ LocalizeText('inventory.empty.pets.title') } />;
|
||||
|
||||
return (
|
||||
<Grid>
|
||||
<Column overflow="hidden" size={ 7 }>
|
||||
<AutoGrid columnCount={ 5 }>
|
||||
{ petItems && (petItems.length > 0) && petItems.map(item => <InventoryPetItemView key={ item.petData.id } petItem={ item } />) }
|
||||
</AutoGrid>
|
||||
</Column>
|
||||
<Column overflow="auto" size={ 5 }>
|
||||
<Column overflow="hidden" position="relative">
|
||||
<div className="grid h-full grid-cols-12 gap-2">
|
||||
<div className="flex flex-col col-span-7 gap-1 overflow-hidden">
|
||||
<InfiniteGrid<IPetItem>
|
||||
columnCount={ 6 }
|
||||
itemRender={ item => <InventoryPetItemView petItem={ item } /> }
|
||||
items={ petItems } />
|
||||
</div>
|
||||
<div className="flex flex-col col-span-5">
|
||||
<div className="relative flex flex-col">
|
||||
<LayoutRoomPreviewerView height={ 140 } roomPreviewer={ roomPreviewer } />
|
||||
</Column>
|
||||
</div>
|
||||
{ selectedPet && selectedPet.petData &&
|
||||
<Column grow gap={ 2 } justifyContent="between">
|
||||
<Text grow truncate>{ selectedPet.petData.name }</Text>
|
||||
<div className="flex flex-col justify-between gap-2 grow">
|
||||
<span className="text-sm truncate grow">{ selectedPet.petData.name }</span>
|
||||
{ !!roomSession &&
|
||||
<Button variant="success" onClick={ event => attemptPetPlacement(selectedPet) }>
|
||||
<NitroButton onClick={ event => attemptPetPlacement(selectedPet) }>
|
||||
{ LocalizeText('inventory.furni.placetoroom') }
|
||||
</Button> }
|
||||
</Column> }
|
||||
</Column>
|
||||
</Grid>
|
||||
</NitroButton> }
|
||||
</div> }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -69,9 +69,10 @@ const InfiniteGridRoot = <T,>(props: Props<T>) =>
|
||||
<div
|
||||
key={ virtualRow.key + 'a' }
|
||||
ref={ virtualizer.measureElement }
|
||||
className={ `grid grid-cols-${ columnCount } gap-1 absolute top-0 left-0 h-[45px] last:pb-0 w-full` }
|
||||
className={ `grid grid-cols-${ columnCount } gap-1 absolute top-0 left-0 last:pb-0 w-full` }
|
||||
data-index={ virtualRow.index }
|
||||
style={ {
|
||||
height: virtualRow.size,
|
||||
transform: `translateY(${ virtualRow.start }px)`
|
||||
} }>
|
||||
{ Array.from(Array(columnCount)).map((e,i) =>
|
||||
@ -142,7 +143,7 @@ const InfiniteGridItem = forwardRef<HTMLDivElement, {
|
||||
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',
|
||||
(itemImage && (!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',
|
||||
(itemUniqueSoldout || (itemUniqueNumber > 0)) && 'unique-item',
|
||||
itemUniqueSoldout && 'sold-out',
|
||||
|
44
src/layout/NitroButton.tsx
Normal file
44
src/layout/NitroButton.tsx
Normal file
@ -0,0 +1,44 @@
|
||||
import { ButtonHTMLAttributes, DetailedHTMLProps, forwardRef, PropsWithChildren } from 'react';
|
||||
import { classNames } from './classNames';
|
||||
|
||||
const classes = {
|
||||
base: 'inline-flex justify-center items-center gap-2 transition-[background-color] duration-300 transform tracking-wide rounded-md',
|
||||
disabled: '',
|
||||
size: {
|
||||
default: 'px-2 py-0.5 text-sm font-medium',
|
||||
lg: 'px-5 py-3 text-base font-medium',
|
||||
xl: 'px-6 py-3.5 text-base font-medium',
|
||||
},
|
||||
outline: {
|
||||
default: 'text-blue-700 hover:text-white border border-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 dark:border-blue-500 dark:text-blue-500 dark:hover:text-white dark:hover:bg-blue-600 dark:focus:ring-blue-800'
|
||||
},
|
||||
color: {
|
||||
default: 'bg-button-gradient-gray border border-gray-500',
|
||||
}
|
||||
}
|
||||
|
||||
export const NitroButton = forwardRef<HTMLButtonElement, PropsWithChildren<{
|
||||
color?: 'default' | 'dark' | 'ghost';
|
||||
size?: 'default' | 'lg' | 'xl';
|
||||
outline?: boolean;
|
||||
}> & DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>>((props, ref) =>
|
||||
{
|
||||
const { color = 'default', size = 'default', outline = false, disabled = false, type = 'button', className = null, ...rest } = props;
|
||||
|
||||
return (
|
||||
<button
|
||||
ref={ ref }
|
||||
className={ classNames(
|
||||
classes.base,
|
||||
classes.size[size],
|
||||
outline ? classes.outline[color] : classes.color[color],
|
||||
disabled && classes.disabled,
|
||||
className
|
||||
) }
|
||||
disabled={ disabled }
|
||||
type={ type }
|
||||
{ ...rest } />
|
||||
);
|
||||
});
|
||||
|
||||
NitroButton.displayName = 'NitroButton';
|
42
src/layout/NitroInput.tsx
Normal file
42
src/layout/NitroInput.tsx
Normal file
@ -0,0 +1,42 @@
|
||||
import { DetailedHTMLProps, forwardRef, InputHTMLAttributes, PropsWithChildren } from 'react';
|
||||
import { classNames } from './classNames';
|
||||
|
||||
const classes = {
|
||||
base: 'block w-full placeholder-gray-400 border border-gray-300 shadow-sm appearance-none',
|
||||
disabled: '',
|
||||
size: {
|
||||
default: 'px-2 py-2 text-sm font-medium',
|
||||
},
|
||||
rounded: 'rounded-md',
|
||||
color: {
|
||||
default: 'focus:outline-none focus:ring-indigo-500 focus:border-indigo-500',
|
||||
}
|
||||
}
|
||||
|
||||
export const NitroInput = forwardRef<HTMLInputElement, PropsWithChildren<{
|
||||
color?: 'default' | 'dark' | 'ghost';
|
||||
inputSize?: 'xs' | 'sm' | 'default' | 'lg' | 'xl';
|
||||
rounded?: boolean;
|
||||
}> & DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>>((props, ref) =>
|
||||
{
|
||||
const { color = 'default', inputSize = 'default', rounded = true, disabled = false, type = 'text', autoComplete = 'off', className = null, ...rest } = props;
|
||||
|
||||
return (
|
||||
<input
|
||||
ref={ ref }
|
||||
autoComplete={ autoComplete }
|
||||
className={ classNames(
|
||||
classes.base,
|
||||
classes.size[inputSize],
|
||||
rounded && classes.rounded,
|
||||
classes.color[color],
|
||||
disabled && classes.disabled,
|
||||
className
|
||||
) }
|
||||
disabled={ disabled }
|
||||
type={ type }
|
||||
{ ...rest } />
|
||||
);
|
||||
});
|
||||
|
||||
NitroInput.displayName = 'NitroInput';
|
@ -1,5 +1,7 @@
|
||||
export * from './InfiniteGrid';
|
||||
export * from './NitroButton';
|
||||
export * from './NitroCard';
|
||||
export * from './NitroInput';
|
||||
export * from './NitroItemCountBadge';
|
||||
export * from './classNames';
|
||||
export * from './limited-edition';
|
||||
|
@ -19,7 +19,8 @@ const colors = {
|
||||
};
|
||||
|
||||
const boxShadow = {
|
||||
'inner1px': 'inset 0 0 0 1px rgba(255,255,255,.3)'
|
||||
'inner1px': 'inset 0 0 0 1px rgba(255,255,255,.3)',
|
||||
'room-previewer': '-2px -2px rgba(0, 0, 0, 0.4), inset 3px 3px rgba(0, 0, 0, 0.2);'
|
||||
};
|
||||
|
||||
|
||||
@ -31,6 +32,9 @@ module.exports = {
|
||||
},
|
||||
colors: generateShades(colors),
|
||||
boxShadow,
|
||||
backgroundImage: {
|
||||
'button-gradient-gray': 'linear-gradient(to bottom, #e2e2e2 50%, #c8c8c8 50%)',
|
||||
},
|
||||
spacing: {
|
||||
'card-header': '33px',
|
||||
'card-tabs': '33px',
|
||||
|
Loading…
Reference in New Issue
Block a user