mirror of
https://github.com/duckietm/Nitro-Cool-UI.git
synced 2025-06-21 22:36:58 +00:00
🆙 Fix Pet Infostand
This commit is contained in:
parent
23c8eab372
commit
aee7ffb392
@ -69,6 +69,8 @@ export const LayoutBadgeImageView: FC<LayoutBadgeImageViewProps> = props =>
|
||||
|
||||
const element = await TextureUtils.generateImage(new NitroSprite(event.image));
|
||||
|
||||
console.log ('boe');
|
||||
|
||||
element.onload = () => setImageElement(element);
|
||||
|
||||
didSetBadge = true;
|
||||
@ -86,6 +88,7 @@ export const LayoutBadgeImageView: FC<LayoutBadgeImageViewProps> = props =>
|
||||
{
|
||||
const element = await TextureUtils.generateImage(new NitroSprite(texture));
|
||||
|
||||
|
||||
element.onload = () => setImageElement(element);
|
||||
})();
|
||||
}
|
||||
|
@ -1,57 +1,240 @@
|
||||
import { CreateLinkEvent, PetRespectComposer, PetType } from '@nitrots/nitro-renderer';
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { FC, useEffect, useState, useCallback } from 'react';
|
||||
import { FaTimes } from 'react-icons/fa';
|
||||
import { AvatarInfoPet, ConvertSeconds, GetConfigurationValue, LocalizeText, SendMessageComposer } from '../../../../../api';
|
||||
import { Button, Column, Flex, LayoutCounterTimeView, LayoutPetImageView, LayoutRarityLevelView, Text, UserProfileIconView } from '../../../../../common';
|
||||
import { useRoom, useSessionInfo } from '../../../../../hooks';
|
||||
|
||||
interface InfoStandWidgetPetViewProps
|
||||
{
|
||||
// TypeScript interface for AvatarInfoPet
|
||||
interface AvatarInfoPet {
|
||||
id: number;
|
||||
name: string;
|
||||
petType: number;
|
||||
petBreed: number;
|
||||
petFigure: string;
|
||||
posture: string;
|
||||
level: number;
|
||||
maximumLevel: number;
|
||||
age: number;
|
||||
ownerId: number;
|
||||
ownerName: string;
|
||||
respect: number;
|
||||
dead?: boolean;
|
||||
energy?: number;
|
||||
maximumEnergy?: number;
|
||||
happyness?: number;
|
||||
maximumHappyness?: number;
|
||||
experience?: number;
|
||||
levelExperienceGoal?: number;
|
||||
remainingGrowTime?: number;
|
||||
remainingTimeToLive?: number;
|
||||
maximumTimeToLive?: number;
|
||||
rarityLevel?: number;
|
||||
isOwner?: boolean;
|
||||
}
|
||||
|
||||
interface InfoStandWidgetPetViewProps {
|
||||
avatarInfo: AvatarInfoPet;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export const InfoStandWidgetPetView: FC<InfoStandWidgetPetViewProps> = props =>
|
||||
{
|
||||
const { avatarInfo = null, onClose = null } = props;
|
||||
const [ remainingGrowTime, setRemainingGrowTime ] = useState(0);
|
||||
const [ remainingTimeToLive, setRemainingTimeToLive ] = useState(0);
|
||||
const PetHeader: FC<{ name: string; petType: number; petBreed: number; onClose: () => void }> = ({ name, petType, petBreed, onClose }) => (
|
||||
<div className="flex flex-col gap-1">
|
||||
<Flex alignItems="center" gap={1} justifyContent="between">
|
||||
<Text small wrap variant="white">
|
||||
{name}
|
||||
</Text>
|
||||
<FaTimes
|
||||
className="cursor-pointer fa-icon"
|
||||
onClick={onClose}
|
||||
aria-label={LocalizeText('generic.close')}
|
||||
title={LocalizeText('generic.close')}
|
||||
/>
|
||||
</Flex>
|
||||
<Text small wrap variant="white">
|
||||
{LocalizeText(`pet.breed.${petType}.${petBreed}`)}
|
||||
</Text>
|
||||
<hr className="m-0" />
|
||||
</div>
|
||||
);
|
||||
|
||||
const MonsterplantStats: FC<{
|
||||
avatarInfo: AvatarInfoPet;
|
||||
remainingGrowTime: number;
|
||||
remainingTimeToLive: number;
|
||||
}> = ({ avatarInfo, remainingGrowTime, remainingTimeToLive }) => (
|
||||
<>
|
||||
<Column center gap={1}>
|
||||
<LayoutPetImageView direction={4} figure={avatarInfo.petFigure} posture={avatarInfo.posture} />
|
||||
<hr className="m-0" />
|
||||
</Column>
|
||||
<div className="flex flex-col gap-2">
|
||||
{!avatarInfo.dead && (
|
||||
<Column alignItems="center" gap={1}>
|
||||
<Text center small wrap variant="white">
|
||||
{LocalizeText('pet.level', ['level', 'maxlevel'], [avatarInfo.level.toString(), avatarInfo.maximumLevel.toString()])}
|
||||
</Text>
|
||||
</Column>
|
||||
)}
|
||||
<Column alignItems="center" gap={1}>
|
||||
<Text small truncate variant="white">
|
||||
{LocalizeText('infostand.pet.text.wellbeing')}
|
||||
</Text>
|
||||
<div className="bg-light-dark rounded relative overflow-hidden w-full">
|
||||
<div className="flex justify-center items-center size-full absolute">
|
||||
<Text small variant="white">
|
||||
{avatarInfo.dead || remainingTimeToLive <= 0
|
||||
? '00:00:00'
|
||||
: `${ConvertSeconds(remainingTimeToLive).split(':')[1]}:${ConvertSeconds(remainingTimeToLive).split(':')[2]}:${ConvertSeconds(remainingTimeToLive).split(':')[3]}`}
|
||||
</Text>
|
||||
</div>
|
||||
<div
|
||||
className="bg-success rounded pet-stats"
|
||||
style={{
|
||||
width: avatarInfo.dead || remainingTimeToLive <= 0 ? '0' : `${(remainingTimeToLive / avatarInfo.maximumTimeToLive) * 100}%`,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Column>
|
||||
{remainingGrowTime > 0 && (
|
||||
<Column alignItems="center" gap={1}>
|
||||
<Text small truncate variant="white">
|
||||
{LocalizeText('infostand.pet.text.growth')}
|
||||
</Text>
|
||||
<LayoutCounterTimeView
|
||||
className="top-2 end-2"
|
||||
day={ConvertSeconds(remainingGrowTime).split(':')[0]}
|
||||
hour={ConvertSeconds(remainingGrowTime).split(':')[1]}
|
||||
minutes={ConvertSeconds(remainingGrowTime).split(':')[2]}
|
||||
seconds={ConvertSeconds(remainingGrowTime).split(':')[3]}
|
||||
/>
|
||||
</Column>
|
||||
)}
|
||||
<Column alignItems="center" gap={1}>
|
||||
<Text small truncate variant="white">
|
||||
{LocalizeText('infostand.pet.text.raritylevel', ['level'], [LocalizeText(`infostand.pet.raritylevel.${avatarInfo.rarityLevel}`)])}
|
||||
</Text>
|
||||
<LayoutRarityLevelView className="top-2 end-2" level={avatarInfo.rarityLevel} />
|
||||
</Column>
|
||||
<hr className="m-0" />
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<Text small wrap variant="white">
|
||||
{LocalizeText('pet.age', ['age'], [avatarInfo.age.toString()])}
|
||||
</Text>
|
||||
<hr className="m-0" />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
// Sub-component: Regular Pet Stats
|
||||
const RegularPetStats: FC<{ avatarInfo: AvatarInfoPet }> = ({ avatarInfo }) => (
|
||||
<>
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="flex gap-1">
|
||||
<Column fullWidth className="body-image pet p-1" overflow="hidden">
|
||||
<LayoutPetImageView direction={4} figure={avatarInfo.petFigure} posture={avatarInfo.posture} />
|
||||
</Column>
|
||||
<Column grow gap={1}>
|
||||
<Text center small wrap variant="white">
|
||||
{LocalizeText('pet.level', ['level', 'maxlevel'], [avatarInfo.level.toString(), avatarInfo.maximumLevel.toString()])}
|
||||
</Text>
|
||||
<Column alignItems="center" gap={1}>
|
||||
<Text small truncate variant="white">
|
||||
{LocalizeText('infostand.pet.text.happiness')}
|
||||
</Text>
|
||||
<div className="bg-light-dark rounded relative overflow-hidden w-full">
|
||||
<div className="flex justify-center items-center size-full absolute">
|
||||
<Text small variant="white">
|
||||
{avatarInfo.happyness + '/' + avatarInfo.maximumHappyness}
|
||||
</Text>
|
||||
</div>
|
||||
<div
|
||||
className="bg-info rounded pet-stats"
|
||||
style={{ width: (avatarInfo.happyness / avatarInfo.maximumHappyness) * 100 + '%' }}
|
||||
/>
|
||||
</div>
|
||||
</Column>
|
||||
<Column alignItems="center" gap={1}>
|
||||
<Text small truncate variant="white">
|
||||
{LocalizeText('infostand.pet.text.experience')}
|
||||
</Text>
|
||||
<div className="bg-light-dark rounded relative overflow-hidden w-full">
|
||||
<div className="flex justify-center items-center size-full absolute">
|
||||
<Text small variant="white">
|
||||
{avatarInfo.experience + '/' + avatarInfo.levelExperienceGoal}
|
||||
</Text>
|
||||
</div>
|
||||
<div
|
||||
className="bg-purple rounded pet-stats"
|
||||
style={{ width: (avatarInfo.experience / avatarInfo.levelExperienceGoal) * 100 + '%' }}
|
||||
/>
|
||||
</div>
|
||||
</Column>
|
||||
<Column alignItems="center" gap={1}>
|
||||
<Text small truncate variant="white">
|
||||
{LocalizeText('infostand.pet.text.energy')}
|
||||
</Text>
|
||||
<div className="bg-light-dark rounded relative overflow-hidden w-full">
|
||||
<div className="flex justify-center items-center size-full absolute">
|
||||
<Text small variant="white">
|
||||
{avatarInfo.energy + '/' + avatarInfo.maximumEnergy}
|
||||
</Text>
|
||||
</div>
|
||||
<div
|
||||
className="bg-success rounded pet-stats"
|
||||
style={{ width: (avatarInfo.energy / avatarInfo.maximumEnergy) * 100 + '%' }}
|
||||
/>
|
||||
</div>
|
||||
</Column>
|
||||
</Column>
|
||||
</div>
|
||||
<hr className="m-0" />
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<Text small wrap variant="white">
|
||||
{LocalizeText('infostand.text.petrespect', ['count'], [avatarInfo.respect.toString()])}
|
||||
</Text>
|
||||
<Text small wrap variant="white">
|
||||
{LocalizeText('pet.age', ['age'], [avatarInfo.age.toString()])}
|
||||
</Text>
|
||||
<hr className="m-0" />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
export const InfoStandWidgetPetView: FC<InfoStandWidgetPetViewProps> = ({ avatarInfo, onClose }) => {
|
||||
const [remainingGrowTime, setRemainingGrowTime] = useState(0);
|
||||
const [remainingTimeToLive, setRemainingTimeToLive] = useState(0);
|
||||
const { roomSession = null } = useRoom();
|
||||
const { petRespectRemaining = 0, respectPet = null } = useSessionInfo();
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
setRemainingGrowTime(avatarInfo.remainingGrowTime);
|
||||
setRemainingTimeToLive(avatarInfo.remainingTimeToLive);
|
||||
}, [ avatarInfo ]);
|
||||
useEffect(() => {
|
||||
setRemainingGrowTime(avatarInfo.remainingGrowTime || 0);
|
||||
setRemainingTimeToLive(avatarInfo.remainingTimeToLive || 0);
|
||||
}, [avatarInfo]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if((avatarInfo.petType !== PetType.MONSTERPLANT) || avatarInfo.dead) return;
|
||||
useEffect(() => {
|
||||
if (avatarInfo.petType !== PetType.MONSTERPLANT || avatarInfo.dead) return;
|
||||
|
||||
const interval = setInterval(() =>
|
||||
{
|
||||
setRemainingGrowTime(prevValue => (prevValue - 1));
|
||||
setRemainingTimeToLive(prevValue => (prevValue - 1));
|
||||
const interval = setInterval(() => {
|
||||
setRemainingGrowTime((prev) => (prev <= 0 ? 0 : prev - 1));
|
||||
setRemainingTimeToLive((prev) => (prev <= 0 ? 0 : prev - 1));
|
||||
}, 1000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, [ avatarInfo ]);
|
||||
}, [avatarInfo]);
|
||||
|
||||
if(!avatarInfo) return null;
|
||||
|
||||
const processButtonAction = (action: string) =>
|
||||
{
|
||||
const processButtonAction = useCallback(
|
||||
async (action: string) => {
|
||||
try {
|
||||
let hideMenu = true;
|
||||
if (!action) return;
|
||||
|
||||
if(!action || action == '') return;
|
||||
|
||||
switch(action)
|
||||
{
|
||||
switch (action) {
|
||||
case 'respect':
|
||||
respectPet(avatarInfo.id);
|
||||
|
||||
if((petRespectRemaining - 1) >= 1) hideMenu = false;
|
||||
await respectPet(avatarInfo.id);
|
||||
if (petRespectRemaining - 1 >= 1) hideMenu = false;
|
||||
break;
|
||||
case 'buyfood':
|
||||
CreateLinkEvent('catalog/open/' + GetConfigurationValue('catalog.links')['pets.buy_food']);
|
||||
@ -70,139 +253,90 @@ export const InfoStandWidgetPetView: FC<InfoStandWidgetPetViewProps> = props =>
|
||||
break;
|
||||
}
|
||||
|
||||
if(hideMenu) onClose();
|
||||
};
|
||||
if (hideMenu) onClose();
|
||||
} catch (error) {
|
||||
console.error(`Failed to process action ${action}:`, error);
|
||||
}
|
||||
},
|
||||
[avatarInfo, petRespectRemaining, respectPet, roomSession, onClose]
|
||||
);
|
||||
|
||||
const buttons = [
|
||||
{
|
||||
action: 'buyfood',
|
||||
label: LocalizeText('infostand.button.buyfood'),
|
||||
condition: avatarInfo.petType !== PetType.MONSTERPLANT,
|
||||
},
|
||||
{
|
||||
action: 'train',
|
||||
label: LocalizeText('infostand.button.train'),
|
||||
condition: avatarInfo.isOwner && avatarInfo.petType !== PetType.MONSTERPLANT,
|
||||
},
|
||||
{
|
||||
action: 'treat',
|
||||
label: LocalizeText('infostand.button.pettreat'),
|
||||
condition:
|
||||
!avatarInfo.dead &&
|
||||
avatarInfo.petType === PetType.MONSTERPLANT &&
|
||||
avatarInfo.energy / avatarInfo.maximumEnergy < 0.98,
|
||||
},
|
||||
{
|
||||
action: 'compost',
|
||||
label: LocalizeText('infostand.button.compost'),
|
||||
condition: roomSession?.isRoomOwner && avatarInfo.petType === PetType.MONSTERPLANT,
|
||||
},
|
||||
{
|
||||
action: 'pick_up',
|
||||
label: LocalizeText('inventory.pets.pickup'),
|
||||
condition: avatarInfo.isOwner,
|
||||
},
|
||||
{
|
||||
action: 'respect',
|
||||
label: LocalizeText('infostand.button.petrespect', ['count'], [petRespectRemaining.toString()]),
|
||||
condition: petRespectRemaining > 0 && avatarInfo.petType !== PetType.MONSTERPLANT,
|
||||
},
|
||||
];
|
||||
|
||||
if (!avatarInfo) return <Text variant="white">{LocalizeText('generic.loading')}</Text>;
|
||||
|
||||
return (
|
||||
<Column alignItems="end" gap={ 1 }>
|
||||
<Column alignItems="end" gap={1}>
|
||||
<Column className="nitro-infostand rounded">
|
||||
<Column className="container-fluid content-area" gap={ 1 } overflow="visible">
|
||||
<div className="flex flex-col gap-1">
|
||||
<Flex alignItems="center" gap={ 1 } justifyContent="between">
|
||||
<Text small wrap variant="white">{ avatarInfo.name }</Text>
|
||||
<FaTimes className="cursor-pointer fa-icon" onClick={ onClose } />
|
||||
</Flex>
|
||||
<Text small wrap variant="white">{ LocalizeText(`pet.breed.${ avatarInfo.petType }.${ avatarInfo.petBreed }`) }</Text>
|
||||
<hr className="m-0" />
|
||||
</div>
|
||||
{ (avatarInfo.petType === PetType.MONSTERPLANT) &&
|
||||
<>
|
||||
<Column center gap={ 1 }>
|
||||
<LayoutPetImageView direction={ 4 } figure={ avatarInfo.petFigure } posture={ avatarInfo.posture } />
|
||||
<hr className="m-0" />
|
||||
</Column>
|
||||
<div className="flex flex-col gap-2">
|
||||
{ !avatarInfo.dead &&
|
||||
<Column alignItems="center" gap={ 1 }>
|
||||
<Text center small wrap variant="white">{ LocalizeText('pet.level', [ 'level', 'maxlevel' ], [ avatarInfo.level.toString(), avatarInfo.maximumLevel.toString() ]) }</Text>
|
||||
</Column> }
|
||||
<Column alignItems="center" gap={ 1 }>
|
||||
<Text small truncate variant="white">{ LocalizeText('infostand.pet.text.wellbeing') }</Text>
|
||||
<div className="bg-light-dark rounded relative overflow-hidden w-full">
|
||||
<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>
|
||||
</div>
|
||||
<div className="bg-success rounded pet-stats" style={ { width: avatarInfo.dead ? '0' : Math.round((avatarInfo.maximumTimeToLive * 100) / (remainingTimeToLive)).toString() } } />
|
||||
</div>
|
||||
</Column>
|
||||
{ remainingGrowTime != 0 && remainingGrowTime > 0 &&
|
||||
<Column alignItems="center" gap={ 1 }>
|
||||
<Text small truncate variant="white">{ LocalizeText('infostand.pet.text.growth') }</Text>
|
||||
<LayoutCounterTimeView className="top-2 end-2" day={ ConvertSeconds(remainingGrowTime).split(':')[0] } hour={ ConvertSeconds(remainingGrowTime).split(':')[1] } minutes={ ConvertSeconds(remainingGrowTime).split(':')[2] } seconds={ ConvertSeconds(remainingGrowTime).split(':')[3] } />
|
||||
</Column> }
|
||||
<Column alignItems="center" gap={ 1 }>
|
||||
<Text small truncate variant="white">{ LocalizeText('infostand.pet.text.raritylevel', [ 'level' ], [ LocalizeText(`infostand.pet.raritylevel.${ avatarInfo.rarityLevel }`) ]) }</Text>
|
||||
<LayoutRarityLevelView className="top-2 end-2" level={ avatarInfo.rarityLevel } />
|
||||
</Column>
|
||||
<hr className="m-0" />
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<Text small wrap variant="white">{ LocalizeText('pet.age', [ 'age' ], [ avatarInfo.age.toString() ]) }</Text>
|
||||
<hr className="m-0" />
|
||||
</div>
|
||||
</> }
|
||||
{ (avatarInfo.petType !== PetType.MONSTERPLANT) &&
|
||||
<>
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="flex gap-1">
|
||||
<Column fullWidth className="body-image pet p-1" overflow="hidden">
|
||||
<LayoutPetImageView direction={ 4 } figure={ avatarInfo.petFigure } posture={ avatarInfo.posture } />
|
||||
</Column>
|
||||
<Column grow gap={ 1 }>
|
||||
<Text center small wrap variant="white">{ LocalizeText('pet.level', [ 'level', 'maxlevel' ], [ avatarInfo.level.toString(), avatarInfo.maximumLevel.toString() ]) }</Text>
|
||||
<Column alignItems="center" gap={ 1 }>
|
||||
<Text small truncate variant="white">{ LocalizeText('infostand.pet.text.happiness') }</Text>
|
||||
<div className="bg-light-dark rounded relative overflow-hidden w-full">
|
||||
<div className="flex justify-center items-center size-full absolute">
|
||||
<Text small variant="white">{ avatarInfo.happyness + '/' + avatarInfo.maximumHappyness }</Text>
|
||||
</div>
|
||||
<div className="bg-info rounded pet-stats" style={ { width: (avatarInfo.happyness / avatarInfo.maximumHappyness) * 100 + '%' } } />
|
||||
</div>
|
||||
</Column>
|
||||
<Column alignItems="center" gap={ 1 }>
|
||||
<Text small truncate variant="white">{ LocalizeText('infostand.pet.text.experience') }</Text>
|
||||
<div className="bg-light-dark rounded relative overflow-hidden w-full">
|
||||
<div className="flex justify-center items-center size-full absolute">
|
||||
<Text small variant="white">{ avatarInfo.experience + '/' + avatarInfo.levelExperienceGoal }</Text>
|
||||
</div>
|
||||
<div className="bg-purple rounded pet-stats" style={ { width: (avatarInfo.experience / avatarInfo.levelExperienceGoal) * 100 + '%' } } />
|
||||
</div>
|
||||
</Column>
|
||||
<Column alignItems="center" gap={ 1 }>
|
||||
<Text small truncate variant="white">{ LocalizeText('infostand.pet.text.energy') }</Text>
|
||||
<div className="bg-light-dark rounded relative overflow-hidden w-full">
|
||||
<div className="flex justify-center items-center size-full absolute">
|
||||
<Text small variant="white">{ avatarInfo.energy + '/' + avatarInfo.maximumEnergy }</Text>
|
||||
</div>
|
||||
<div className="bg-success rounded pet-stats" style={ { width: (avatarInfo.energy / avatarInfo.maximumEnergy) * 100 + '%' } } />
|
||||
</div>
|
||||
</Column>
|
||||
</Column>
|
||||
</div>
|
||||
<hr className="m-0" />
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
{ (avatarInfo.petType !== PetType.MONSTERPLANT) &&
|
||||
<Text small wrap variant="white">{ LocalizeText('infostand.text.petrespect', [ 'count' ], [ avatarInfo.respect.toString() ]) }</Text> }
|
||||
<Text small wrap variant="white">{ LocalizeText('pet.age', [ 'age' ], [ avatarInfo.age.toString() ]) }</Text>
|
||||
<hr className="m-0" />
|
||||
</div>
|
||||
</> }
|
||||
<Column className="container-fluid content-area" gap={1} overflow="visible">
|
||||
<PetHeader
|
||||
name={avatarInfo.name}
|
||||
petType={avatarInfo.petType}
|
||||
petBreed={avatarInfo.petBreed}
|
||||
onClose={onClose}
|
||||
/>
|
||||
{avatarInfo.petType === PetType.MONSTERPLANT ? (
|
||||
<MonsterplantStats
|
||||
avatarInfo={avatarInfo}
|
||||
remainingGrowTime={remainingGrowTime}
|
||||
remainingTimeToLive={remainingTimeToLive}
|
||||
/>
|
||||
) : (
|
||||
<RegularPetStats avatarInfo={avatarInfo} />
|
||||
)}
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="flex items-center gap-1">
|
||||
<UserProfileIconView userId={ avatarInfo.ownerId } />
|
||||
<UserProfileIconView userId={avatarInfo.ownerId} />
|
||||
<Text small wrap variant="white">
|
||||
{ LocalizeText('infostand.text.petowner', [ 'name' ], [ avatarInfo.ownerName ]) }
|
||||
{LocalizeText('infostand.text.petowner', ['name'], [avatarInfo.ownerName])}
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
</Column>
|
||||
</Column>
|
||||
<Flex gap={ 1 } justifyContent="end">
|
||||
{ (avatarInfo.petType !== PetType.MONSTERPLANT) &&
|
||||
<Button variant="dark" onClick={ event => processButtonAction('buyfood') }>
|
||||
{ LocalizeText('infostand.button.buyfood') }
|
||||
</Button> }
|
||||
{ avatarInfo.isOwner && (avatarInfo.petType !== PetType.MONSTERPLANT) &&
|
||||
<Button variant="dark" onClick={ event => processButtonAction('train') }>
|
||||
{ LocalizeText('infostand.button.train') }
|
||||
</Button> }
|
||||
{ !avatarInfo.dead && ((avatarInfo.energy / avatarInfo.maximumEnergy) < 0.98) && (avatarInfo.petType === PetType.MONSTERPLANT) &&
|
||||
<Button variant="dark" onClick={ event => processButtonAction('treat') }>
|
||||
{ LocalizeText('infostand.button.pettreat') }
|
||||
</Button> }
|
||||
{ roomSession?.isRoomOwner && (avatarInfo.petType === PetType.MONSTERPLANT) &&
|
||||
<Button variant="dark" onClick={ event => processButtonAction('compost') }>
|
||||
{ LocalizeText('infostand.button.compost') }
|
||||
</Button> }
|
||||
{ avatarInfo.isOwner &&
|
||||
<Button variant="dark" onClick={ event => processButtonAction('pick_up') }>
|
||||
{ LocalizeText('inventory.pets.pickup') }
|
||||
</Button> }
|
||||
{ (petRespectRemaining > 0) && (avatarInfo.petType !== PetType.MONSTERPLANT) &&
|
||||
<Button variant="dark" onClick={ event => processButtonAction('respect') }>
|
||||
{ LocalizeText('infostand.button.petrespect', [ 'count' ], [ petRespectRemaining.toString() ]) }
|
||||
</Button> }
|
||||
<Flex gap={1} justifyContent="end">
|
||||
{buttons.map(
|
||||
(button) =>
|
||||
button.condition && (
|
||||
<Button key={button.action} variant="dark" onClick={() => processButtonAction(button.action)}>
|
||||
{button.label}
|
||||
</Button>
|
||||
)
|
||||
)}
|
||||
</Flex>
|
||||
</Column>
|
||||
);
|
||||
|
145
src/css/room/InfoStand.css
Normal file
145
src/css/room/InfoStand.css
Normal file
@ -0,0 +1,145 @@
|
||||
.nitro-use-product-confirmation {
|
||||
width: 350px;
|
||||
|
||||
.product-preview {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 75px; /* Aligned with .body-image.pet */
|
||||
height: 80px;
|
||||
background: url('@/assets/images/room-widgets/avatar-info/preview-background.png') no-repeat center;
|
||||
|
||||
.pet-image {
|
||||
width: 75px;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
.monsterplant-image {
|
||||
width: 75px;
|
||||
height: 80px;
|
||||
background: url('@/assets/images/room-widgets/furni-context-menu/monsterplant-preview.png') no-repeat center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nitro-infostand {
|
||||
position: relative;
|
||||
width: clamp(160px, 20vw, 190px); /* Responsive width */
|
||||
z-index: 30;
|
||||
pointer-events: auto;
|
||||
background: #212131;
|
||||
box-shadow: inset 0 5px rgba(38, 38, 57, 0.6), inset 0 -4px rgba(25, 25, 37, 0.6);
|
||||
border-radius: 0.5rem;
|
||||
padding: 10px;
|
||||
|
||||
@media (max-width: 576px) {
|
||||
top: -67px;
|
||||
padding: 8px;
|
||||
.text {
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
}
|
||||
|
||||
.form-control-sm {
|
||||
height: 25px;
|
||||
min-height: 25px;
|
||||
padding: 0.1rem 0.25rem;
|
||||
}
|
||||
|
||||
.body-image {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
max-width: 68px;
|
||||
border-radius: 0.5rem;
|
||||
|
||||
&.pet {
|
||||
max-width: 75px;
|
||||
}
|
||||
|
||||
&.bot {
|
||||
background-image: url('@/assets/images/infostand/bot_background.png');
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
&.furni {
|
||||
background-color: transparent;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.body-image-plant {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
max-width: 68px;
|
||||
height: 85px;
|
||||
max-height: 90px;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.badge-image {
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
}
|
||||
|
||||
.motto-content {
|
||||
min-height: 18px;
|
||||
}
|
||||
|
||||
.motto-input {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: 12px;
|
||||
padding: 0;
|
||||
outline: 0;
|
||||
border: 0;
|
||||
color: rgba(255, 255, 255, 1);
|
||||
position: relative;
|
||||
background: transparent;
|
||||
resize: none;
|
||||
|
||||
&:focus {
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
|
||||
.flex-tags {
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: -10px;
|
||||
|
||||
.text-tags {
|
||||
padding: 2px;
|
||||
border-radius: 3px;
|
||||
background: #333;
|
||||
margin-right: 5px;
|
||||
margin-bottom: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.button-container {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.pet-stats {
|
||||
height: 18px;
|
||||
transition: width 0.3s ease-in-out; /* Smooth progress bar animation */
|
||||
}
|
||||
}
|
||||
|
||||
.nitro-rarity-level {
|
||||
width: 36px;
|
||||
height: 28px;
|
||||
background: url('@/assets/images/infostand/rarity-level.png');
|
||||
|
||||
div {
|
||||
line-height: 28px;
|
||||
text-align: center;
|
||||
color: $black;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
@ -29,6 +29,7 @@ import './css/notification/NotificationCenterView.css';
|
||||
|
||||
import './css/purse/PurseView.css';
|
||||
|
||||
import './css/room/InfoStand.css';
|
||||
import './css/room/NavigatorRoomSettings.css';
|
||||
import './css/room/RoomWidgets.css';
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user