Fix scaling issues

This commit is contained in:
Bill 2022-04-08 01:39:35 -04:00
parent a5a73ba1fb
commit ce623859df
20 changed files with 264 additions and 252 deletions

View File

@ -1,5 +1,5 @@
import { ConfigurationEvent, HabboWebTools, LegacyExternalInterface, Nitro, NitroCommunicationDemoEvent, NitroEvent, NitroLocalizationEvent, NitroVersion, RoomEngineEvent, WebGL } from '@nitrots/nitro-renderer'; import { ConfigurationEvent, HabboWebTools, LegacyExternalInterface, Nitro, NitroCommunicationDemoEvent, NitroEvent, NitroLocalizationEvent, NitroVersion, RoomEngineEvent, WebGL } from '@nitrots/nitro-renderer';
import { FC, useCallback, useState } from 'react'; import { FC, useCallback, useEffect, useState } from 'react';
import { GetCommunication, GetConfiguration, GetNitroInstance, GetUIVersion } from './api'; import { GetCommunication, GetConfiguration, GetNitroInstance, GetUIVersion } from './api';
import { Base, TransitionAnimation, TransitionAnimationTypes } from './common'; import { Base, TransitionAnimation, TransitionAnimationTypes } from './common';
import { LoadingView } from './components/loading/LoadingView'; import { LoadingView } from './components/loading/LoadingView';
@ -16,12 +16,13 @@ export const App: FC<{}> = props =>
const [ isError, setIsError ] = useState(false); const [ isError, setIsError ] = useState(false);
const [ message, setMessage ] = useState('Getting Ready'); const [ message, setMessage ] = useState('Getting Ready');
const [ percent, setPercent ] = useState(0); const [ percent, setPercent ] = useState(0);
const [ imageRendering, setImageRendering ] = useState<boolean>(true);
//@ts-ignore
if(!NitroConfig) throw new Error('NitroConfig is not defined!');
if(!GetNitroInstance()) if(!GetNitroInstance())
{ {
//@ts-ignore
if(!NitroConfig) throw new Error('NitroConfig is not defined!');
Nitro.bootstrap(); Nitro.bootstrap();
const worker = new WorkerBuilder(IntervalWebWorker); const worker = new WorkerBuilder(IntervalWebWorker);
@ -29,28 +30,13 @@ export const App: FC<{}> = props =>
Nitro.instance.setWorker(worker); Nitro.instance.setWorker(worker);
} }
const getPreloadAssetUrls = useCallback(() =>
{
const urls: string[] = [];
const assetUrls = GetConfiguration<string[]>('preload.assets.urls');
if(assetUrls && assetUrls.length)
{
for(const url of assetUrls) urls.push(GetNitroInstance().core.configuration.interpolate(url));
}
return urls;
}, []);
const loadPercent = useCallback(() => setPercent(prevValue => (prevValue + 20)), []);
const handler = useCallback((event: NitroEvent) => const handler = useCallback((event: NitroEvent) =>
{ {
switch(event.type) switch(event.type)
{ {
case ConfigurationEvent.LOADED: case ConfigurationEvent.LOADED:
GetNitroInstance().localization.init(); GetNitroInstance().localization.init();
loadPercent(); setPercent(prevValue => (prevValue + 20));
return; return;
case ConfigurationEvent.FAILED: case ConfigurationEvent.FAILED:
setIsError(true); setIsError(true);
@ -67,14 +53,14 @@ export const App: FC<{}> = props =>
setTimeout(() => window.location.reload(), 1500); setTimeout(() => window.location.reload(), 1500);
return; return;
case NitroCommunicationDemoEvent.CONNECTION_HANDSHAKING: case NitroCommunicationDemoEvent.CONNECTION_HANDSHAKING:
loadPercent(); setPercent(prevValue => (prevValue + 20));
return; return;
case NitroCommunicationDemoEvent.CONNECTION_HANDSHAKE_FAILED: case NitroCommunicationDemoEvent.CONNECTION_HANDSHAKE_FAILED:
setIsError(true); setIsError(true);
setMessage('Handshake Failed'); setMessage('Handshake Failed');
return; return;
case NitroCommunicationDemoEvent.CONNECTION_AUTHENTICATED: case NitroCommunicationDemoEvent.CONNECTION_AUTHENTICATED:
loadPercent(); setPercent(prevValue => (prevValue + 20));
GetNitroInstance().init(); GetNitroInstance().init();
@ -85,26 +71,30 @@ export const App: FC<{}> = props =>
setMessage('Connection Error'); setMessage('Connection Error');
return; return;
case NitroCommunicationDemoEvent.CONNECTION_CLOSED: case NitroCommunicationDemoEvent.CONNECTION_CLOSED:
//if(GetNitroInstance().roomEngine) GetNitroInstance().roomEngine.dispose(); //if(GetNitroInstance().roomEngine) GetNitroInstance().roomEngine.dispose();
//setIsError(true); //setIsError(true);
setMessage('Connection Error'); setMessage('Connection Error');
HabboWebTools.send(-1, 'client.init.handshake.fail'); HabboWebTools.send(-1, 'client.init.handshake.fail');
return; return;
case RoomEngineEvent.ENGINE_INITIALIZED: case RoomEngineEvent.ENGINE_INITIALIZED:
loadPercent(); setPercent(prevValue => (prevValue + 20));
setTimeout(() => setIsReady(true), 300); setTimeout(() => setIsReady(true), 300);
return; return;
case NitroLocalizationEvent.LOADED: case NitroLocalizationEvent.LOADED: {
GetNitroInstance().core.asset.downloadAssets(getPreloadAssetUrls(), (status: boolean) => const assetUrls = GetConfiguration<string[]>('preload.assets.urls');
const urls: string[] = [];
if(assetUrls && assetUrls.length) for(const url of assetUrls) urls.push(GetNitroInstance().core.configuration.interpolate(url));
GetNitroInstance().core.asset.downloadAssets(urls, (status: boolean) =>
{ {
if(status) if(status)
{ {
GetCommunication().init(); GetCommunication().init();
loadPercent(); setPercent(prevValue => (prevValue + 20))
} }
else else
{ {
@ -113,8 +103,9 @@ export const App: FC<{}> = props =>
} }
}); });
return; return;
}
} }
}, [ getPreloadAssetUrls,loadPercent ]); }, []);
UseMainEvent(Nitro.WEBGL_UNAVAILABLE, handler); UseMainEvent(Nitro.WEBGL_UNAVAILABLE, handler);
UseMainEvent(Nitro.WEBGL_CONTEXT_LOST, handler); UseMainEvent(Nitro.WEBGL_CONTEXT_LOST, handler);
@ -128,17 +119,31 @@ export const App: FC<{}> = props =>
UseConfigurationEvent(ConfigurationEvent.LOADED, handler); UseConfigurationEvent(ConfigurationEvent.LOADED, handler);
UseConfigurationEvent(ConfigurationEvent.FAILED, handler); UseConfigurationEvent(ConfigurationEvent.FAILED, handler);
if(!WebGL.isWebGLAvailable()) useEffect(() =>
{ {
DispatchUiEvent(new NitroEvent(Nitro.WEBGL_UNAVAILABLE)); if(!WebGL.isWebGLAvailable())
} {
else DispatchUiEvent(new NitroEvent(Nitro.WEBGL_UNAVAILABLE));
{ }
GetNitroInstance().core.configuration.init(); else
} {
GetNitroInstance().core.configuration.init();
}
const resize = (event: UIEvent) => setImageRendering(!(window.devicePixelRatio % 1));
window.addEventListener('resize', resize);
resize(null);
return () =>
{
window.removeEventListener('resize', resize);
}
}, []);
return ( return (
<Base fit overflow="hidden"> <Base fit overflow="hidden" className={ imageRendering && 'image-rendering-pixelated' }>
{ (!isReady || isError) && { (!isReady || isError) &&
<LoadingView isError={ isError } message={ message } percent={ percent } /> } <LoadingView isError={ isError } message={ message } percent={ percent } /> }
<TransitionAnimation type={ TransitionAnimationTypes.FADE_IN } inProp={ (isReady) }> <TransitionAnimation type={ TransitionAnimationTypes.FADE_IN } inProp={ (isReady) }>

View File

@ -7,8 +7,8 @@ let clickCount = 0;
export const DispatchMouseEvent = (event: MouseEvent, canvasId: number = 1) => export const DispatchMouseEvent = (event: MouseEvent, canvasId: number = 1) =>
{ {
const x = (event.clientX * window.devicePixelRatio); const x = event.clientX;
const y = (event.clientY * window.devicePixelRatio); const y = event.clientY;
let eventType = event.type; let eventType = event.type;

View File

@ -51,9 +51,6 @@ export const DispatchTouchEvent = (event: TouchEvent, canvasId: number = 1, long
y = event.changedTouches[0].clientY; y = event.changedTouches[0].clientY;
} }
x = Math.round(x / (1 / window.devicePixelRatio));
y = Math.round(y / (1 / window.devicePixelRatio));
switch(eventType) switch(eventType)
{ {
case MouseEventType.MOUSE_CLICK: case MouseEventType.MOUSE_CLICK:

View File

@ -6,11 +6,8 @@ export const GetRoomObjectBounds = (roomId: number, objectId: number, category:
if(!rectangle) return null; if(!rectangle) return null;
if(window.devicePixelRatio !== 1) rectangle.x = Math.round(rectangle.x);
{ rectangle.y = Math.round(rectangle.y);
rectangle.x = Math.round(rectangle.x / window.devicePixelRatio);
rectangle.y = Math.round(rectangle.y / window.devicePixelRatio);
}
return rectangle; return rectangle;
} }

View File

@ -6,11 +6,8 @@ export const GetRoomObjectScreenLocation = (roomId: number, objectId: number, ca
if(!point) return null; if(!point) return null;
if(window.devicePixelRatio !== 1) point.x = Math.round(point.x);
{ point.y = Math.round(point.y);
point.x = Math.round(point.x / window.devicePixelRatio);
point.y = Math.round(point.y / window.devicePixelRatio);
}
return point; return point;
} }

View File

@ -16,7 +16,7 @@
cursor: not-allowed; cursor: not-allowed;
img { img {
opacity: .5; opacity: 0.5;
filter: grayscale(1); filter: grayscale(1);
} }
} }
@ -30,9 +30,8 @@
} }
&.has-highlight { &.has-highlight {
&:after { &:after {
content: ''; content: "";
z-index: 2; z-index: 2;
position: absolute; position: absolute;
top: 0; top: 0;
@ -48,7 +47,7 @@
.nitro-room-thumbnail-camera { .nitro-room-thumbnail-camera {
width: 132px; width: 132px;
height: 192px; height: 192px;
background-image: url('../assets/images/room-widgets/thumbnail-widget/thumbnail-camera-spritesheet.png'); background-image: url("../assets/images/room-widgets/thumbnail-widget/thumbnail-camera-spritesheet.png");
.camera-frame { .camera-frame {
position: absolute; position: absolute;
@ -65,10 +64,10 @@
height: 173px; height: 173px;
color: black; color: black;
pointer-events: all; pointer-events: all;
background-position: 0px 0px; background-position: 0px 0px;
background-image: url('../assets/images/room-widgets/trophy-widget/trophy-spritesheet.png'); background-image: url("../assets/images/room-widgets/trophy-widget/trophy-spritesheet.png");
&.trophy-2 { &.trophy-2 {
background-position: 0px 173px; background-position: 0px 173px;
} }
@ -103,7 +102,7 @@
.nitro-gift-card { .nitro-gift-card {
width: 306px; width: 306px;
height: 159px; height: 159px;
background: url('../assets/images/gift/gift_tag.png') center no-repeat; background: url("../assets/images/gift/gift_tag.png") center no-repeat;
.gift-face { .gift-face {
width: 65px; width: 65px;
@ -111,7 +110,8 @@
.gift-incognito { .gift-incognito {
width: 37px; width: 37px;
height: 48px; height: 48px;
background: url('../assets/images/gift/incognito.png') center no-repeat; background: url("../assets/images/gift/incognito.png") center
no-repeat;
} }
.gift-avatar { .gift-avatar {
@ -168,17 +168,26 @@
} }
@-webkit-keyframes sk-bouncedelay { @-webkit-keyframes sk-bouncedelay {
0%, 80%, 100% { -webkit-transform: scale(0) } 0%,
40% { -webkit-transform: scale(1.0) } 80%,
100% {
-webkit-transform: scale(0);
}
40% {
-webkit-transform: scale(1);
}
} }
@keyframes sk-bouncedelay { @keyframes sk-bouncedelay {
0%, 80%, 100% { 0%,
-webkit-transform: scale(0); 80%,
transform: scale(0); 100% {
} 40% { -webkit-transform: scale(0);
-webkit-transform: scale(1.0); transform: scale(0);
transform: scale(1.0); }
40% {
-webkit-transform: scale(1);
transform: scale(1);
} }
} }
@ -186,8 +195,9 @@
position: relative; position: relative;
width: 110px; width: 110px;
height: 110px; height: 110px;
background: url('../assets/images/navigator/thumbnail_placeholder.png') no-repeat center; background: url("../assets/images/navigator/thumbnail_placeholder.png")
background-color: rgba($black, .125); no-repeat center;
background-color: rgba($black, 0.125);
} }
#draggable-windows-container { #draggable-windows-container {
@ -223,7 +233,7 @@
top: 2px; top: 2px;
right: 2px; right: 2px;
font-size: 9.5px; font-size: 9.5px;
padding:2px 3px; padding: 2px 3px;
z-index: 1; z-index: 1;
} }
@ -234,16 +244,6 @@
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center; background-position: center;
&.group-badge {
width: 39px;
height: 39px;
&.scale-2 {
width: 80px;
height: 80px;
}
}
.badge-information { .badge-information {
display: none; display: none;
} }
@ -263,10 +263,10 @@
background: $white; background: $white;
left: -220px; left: -220px;
z-index: 100; z-index: 100;
&:before { &:before {
position: absolute; position: absolute;
content: ' '; content: " ";
width: 0; width: 0;
height: 0; height: 0;
border-left: 10px solid $white; border-left: 10px solid $white;
@ -289,7 +289,7 @@
.nitro-rarity-level { .nitro-rarity-level {
width: 36px; width: 36px;
height: 28px; height: 28px;
background: url('../assets/images/infostand/rarity-level.png'); background: url("../assets/images/infostand/rarity-level.png");
div { div {
line-height: 28px; line-height: 28px;
@ -306,12 +306,6 @@
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center -8px; background-position: center -8px;
pointer-events: none; pointer-events: none;
image-rendering: pixelated;
&.scale-0-5,
&.scale-0-75 {
image-rendering: -webkit-optimize-contrast;
}
} }
.pet-image { .pet-image {
@ -337,7 +331,7 @@
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center; background-position: center;
overflow: hidden; overflow: hidden;
&.border-0 { &.border-0 {
&::after { &::after {
content: none; content: none;
@ -346,7 +340,7 @@
&::after { &::after {
position: absolute; position: absolute;
content: ''; content: "";
top: 0; top: 0;
bottom: 0; bottom: 0;
left: 0; left: 0;
@ -354,13 +348,13 @@
border-radius: $border-radius; border-radius: $border-radius;
border-bottom: 2px solid white; border-bottom: 2px solid white;
border-right: 2px solid white; border-right: 2px solid white;
box-shadow: -2px -2px rgba(0, 0, 0, .4), inset 3px 3px rgba(0, 0, 0, .2); box-shadow: -2px -2px rgba(0, 0, 0, 0.4),
inset 3px 3px rgba(0, 0, 0, 0.2);
} }
} }
} }
.unique-item { .unique-item {
.unique-bg-override { .unique-bg-override {
background-position: center; background-position: center;
background-repeat: no-repeat; background-repeat: no-repeat;
@ -369,26 +363,28 @@
&:before { &:before {
position: absolute; position: absolute;
content: ''; content: "";
width: 100%; width: 100%;
height: 100%; height: 100%;
background: url('../assets/images/unique/grid-bg.png') center no-repeat; background: url("../assets/images/unique/grid-bg.png") center no-repeat;
z-index: 1; z-index: 1;
} }
&:after { &:after {
position: absolute; position: absolute;
content: ''; content: "";
width: 100%; width: 100%;
height: 100%; height: 100%;
background: url('../assets/images/unique/grid-bg-glass.png') center no-repeat; background: url("../assets/images/unique/grid-bg-glass.png") center
no-repeat;
bottom: 0; bottom: 0;
z-index: 4; z-index: 4;
} }
&.sold-out:after { &.sold-out:after {
background: url('../assets/images/unique/grid-bg-sold-out.png') center no-repeat, background: url("../assets/images/unique/grid-bg-sold-out.png") center
url('../assets/images/unique/grid-bg-glass.png') center no-repeat; no-repeat,
url("../assets/images/unique/grid-bg-glass.png") center no-repeat;
} }
.unique-item-counter { .unique-item-counter {
@ -399,7 +395,8 @@
bottom: 1px; bottom: 1px;
width: 100%; width: 100%;
height: 9px; height: 9px;
background: url('../assets/images/unique/grid-count-bg.png') center no-repeat; background: url("../assets/images/unique/grid-count-bg.png") center
no-repeat;
z-index: 3; z-index: 3;
} }
} }
@ -407,7 +404,7 @@
.unique-sold-out-blocker { .unique-sold-out-blocker {
width: 364px; width: 364px;
height: 30px; height: 30px;
background: url('../assets/images/unique/catalog-info-sold-out.png'); background: url("../assets/images/unique/catalog-info-sold-out.png");
div { div {
float: right; float: right;
@ -428,7 +425,7 @@
right: 16px; right: 16px;
width: 34px; width: 34px;
height: 37px; height: 37px;
background: url('../assets/images/unique/inventory-info-amount-bg.png'); background: url("../assets/images/unique/inventory-info-amount-bg.png");
div { div {
display: flex; display: flex;
@ -441,7 +438,8 @@
.unique-complete-plate { .unique-complete-plate {
width: 170px; width: 170px;
height: 29px; height: 29px;
background: url('../assets/images/unique/catalog-info-amount-bg.png') no-repeat center; background: url("../assets/images/unique/catalog-info-amount-bg.png")
no-repeat center;
z-index: 1; z-index: 1;
padding-top: 3px; padding-top: 3px;
@ -462,7 +460,7 @@
outline: 0; outline: 0;
height: 5px; height: 5px;
margin-right: 1px; margin-right: 1px;
background-image: url('../assets/images/unique/numbers.png'); background-image: url("../assets/images/unique/numbers.png");
background-repeat: no-repeat; background-repeat: no-repeat;
&:last-child { &:last-child {
@ -537,7 +535,12 @@
z-index: 1; z-index: 1;
transition: all 1s; transition: all 1s;
border-radius: calc(#{$border-radius} / 2); border-radius: calc(#{$border-radius} / 2);
background: repeating-linear-gradient($tertiary, $tertiary 50%, $quaternary 50%, $quaternary 100%); background: repeating-linear-gradient(
$tertiary,
$tertiary 50%,
$quaternary 50%,
$quaternary 100%
);
} }
.nitro-progress-bar-text { .nitro-progress-bar-text {
@ -546,4 +549,4 @@
} }
} }
@import './card/NitroCardView'; @import "./card/NitroCardView";

View File

@ -23,29 +23,10 @@ export const LayoutAvatarImageView: FC<LayoutAvatarImageViewProps> = props =>
{ {
const newClassNames: string[] = [ 'avatar-image' ]; const newClassNames: string[] = [ 'avatar-image' ];
switch(scale)
{
case .5:
newClassNames.push('scale-0-5');
break;
case .75:
newClassNames.push('scale-0-75');
break;
case 1.25:
newClassNames.push('scale-1-25');
break;
case 1.50:
newClassNames.push('scale-1-50');
break;
default:
newClassNames.push(`scale-${ scale }`);
break;
}
if(classNames.length) newClassNames.push(...classNames); if(classNames.length) newClassNames.push(...classNames);
return newClassNames; return newClassNames;
}, [ scale, classNames ]); }, [ classNames ]);
const getStyle = useMemo(() => const getStyle = useMemo(() =>
{ {
@ -53,10 +34,17 @@ export const LayoutAvatarImageView: FC<LayoutAvatarImageViewProps> = props =>
if(avatarUrl && avatarUrl.length) newStyle.backgroundImage = `url('${ avatarUrl }')`; if(avatarUrl && avatarUrl.length) newStyle.backgroundImage = `url('${ avatarUrl }')`;
if(scale !== 1)
{
newStyle.transform = `scale(${ scale })`;
if(!(scale % 1)) newStyle.imageRendering = 'pixelated';
}
if(Object.keys(style).length) newStyle = { ...newStyle, ...style }; if(Object.keys(style).length) newStyle = { ...newStyle, ...style };
return newStyle; return newStyle;
}, [ avatarUrl, style ]); }, [ avatarUrl, scale, style ]);
useEffect(() => useEffect(() =>
{ {

View File

@ -16,22 +16,7 @@ export interface LayoutBadgeImageViewProps extends BaseProps<HTMLDivElement>
export const LayoutBadgeImageView: FC<LayoutBadgeImageViewProps> = props => export const LayoutBadgeImageView: FC<LayoutBadgeImageViewProps> = props =>
{ {
const { badgeCode = null, isGroup = false, showInfo = false, customTitle = null, isGrayscale = false, scale = 1, classNames = [], style = {}, children = null, ...rest } = props; const { badgeCode = null, isGroup = false, showInfo = false, customTitle = null, isGrayscale = false, scale = 1, classNames = [], style = {}, children = null, ...rest } = props;
const [ badgeUrl, setBadgeUrl ] = useState<string>(''); const [ imageElement, setImageElement ] = useState<HTMLImageElement>(null);
const getScaleClass = useMemo(() =>
{
let scaleName = scale.toString();
if(scale === .5) scaleName = '0-5';
else if(scale === .75) scaleName = '0-75';
else if(scale === 1.25) scaleName = '1-25';
else if(scale === 1.50) scaleName = '1-50';
return `scale-${ scaleName }`;
}, [ scale ]);
const getClassNames = useMemo(() => const getClassNames = useMemo(() =>
{ {
@ -41,23 +26,36 @@ export const LayoutBadgeImageView: FC<LayoutBadgeImageViewProps> = props =>
if(isGrayscale) newClassNames.push('grayscale'); if(isGrayscale) newClassNames.push('grayscale');
if((scale !== 1) && getScaleClass.length) newClassNames.push(getScaleClass);
if(classNames.length) newClassNames.push(...classNames); if(classNames.length) newClassNames.push(...classNames);
return newClassNames; return newClassNames;
}, [ classNames, isGroup, isGrayscale, scale, getScaleClass ]); }, [ classNames, isGroup, isGrayscale ]);
const getStyle = useMemo(() => const getStyle = useMemo(() =>
{ {
let newStyle: CSSProperties = {}; let newStyle: CSSProperties = {};
if(badgeUrl && badgeUrl.length) newStyle.backgroundImage = `url(${ badgeUrl })`; if(imageElement)
{
newStyle.backgroundImage = `url('${ imageElement.src }')`;
newStyle.width = imageElement.width;
newStyle.height = imageElement.height;
if(scale !== 1)
{
newStyle.transform = `scale(${ scale })`;
if(!(scale % 1)) newStyle.imageRendering = 'pixelated';
newStyle.width = (imageElement.width * scale);
newStyle.height = (imageElement.height * scale);
}
}
if(Object.keys(style).length) newStyle = { ...newStyle, ...style }; if(Object.keys(style).length) newStyle = { ...newStyle, ...style };
return newStyle; return newStyle;
}, [ style, badgeUrl ]); }, [ imageElement, scale, style ]);
useEffect(() => useEffect(() =>
{ {
@ -69,7 +67,9 @@ export const LayoutBadgeImageView: FC<LayoutBadgeImageViewProps> = props =>
{ {
if(event.badgeId !== badgeCode) return; if(event.badgeId !== badgeCode) return;
setBadgeUrl(TextureUtils.generateImageUrl(new NitroSprite(event.image))); const element = TextureUtils.generateImage(new NitroSprite(event.image));
element.onload = () => setImageElement(element);
didSetBadge = true; didSetBadge = true;
@ -80,29 +80,23 @@ export const LayoutBadgeImageView: FC<LayoutBadgeImageViewProps> = props =>
const texture = isGroup ? GetSessionDataManager().getGroupBadgeImage(badgeCode) : GetSessionDataManager().getBadgeImage(badgeCode); const texture = isGroup ? GetSessionDataManager().getGroupBadgeImage(badgeCode) : GetSessionDataManager().getBadgeImage(badgeCode);
if(texture && !didSetBadge) setBadgeUrl(TextureUtils.generateImageUrl(new NitroSprite(texture))); if(texture && !didSetBadge)
{
const element = TextureUtils.generateImage(new NitroSprite(texture));
element.onload = () => setImageElement(element);
}
return () => GetSessionDataManager().events.removeEventListener(BadgeImageReadyEvent.IMAGE_READY, onBadgeImageReadyEvent); return () => GetSessionDataManager().events.removeEventListener(BadgeImageReadyEvent.IMAGE_READY, onBadgeImageReadyEvent);
}, [ badgeCode, isGroup ]); }, [ badgeCode, isGroup ]);
const BadgeInformationView = (props: { title: string, description: string }) =>
{
const { title = null, description = null } = props;
if(!GetConfiguration('badge.descriptions.enabled', true)) return null;
return (
<Base className="badge-information text-black py-1 px-2 small">
<div className="fw-bold mb-1">{ title }</div>
<div>{ description }</div>
</Base>
);
};
return ( return (
<Base classNames={ getClassNames } style={ getStyle } { ...rest }> <Base classNames={ getClassNames } style={ getStyle } { ...rest }>
{ showInfo && { (showInfo && GetConfiguration<boolean>('badge.descriptions.enabled', true)) &&
<BadgeInformationView title={ isGroup ? customTitle : LocalizeBadgeName(badgeCode) } description={ isGroup ? LocalizeText('group.badgepopup.body') : LocalizeBadgeDescription(badgeCode) } /> } <Base className="badge-information text-black py-1 px-2 small">
<div className="fw-bold mb-1">{ isGroup ? customTitle : LocalizeBadgeName(badgeCode) }</div>
<div>{ isGroup ? LocalizeText('group.badgepopup.body') : LocalizeBadgeDescription(badgeCode) }</div>
</Base> }
{ children } { children }
</Base> </Base>
); );

View File

@ -1,9 +1,10 @@
import { IGetImageListener, ImageResult, TextureUtils, Vector3d } from '@nitrots/nitro-renderer'; import { IGetImageListener, ImageResult, TextureUtils, Vector3d } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react'; import { CSSProperties, FC, useCallback, useEffect, useMemo, useState } from 'react';
import { BaseProps } from '..';
import { GetRoomEngine, ProductTypeEnum } from '../../api'; import { GetRoomEngine, ProductTypeEnum } from '../../api';
import { Base } from '../Base'; import { Base } from '../Base';
interface LayoutFurniImageViewProps interface LayoutFurniImageViewProps extends BaseProps<HTMLDivElement>
{ {
productType: string; productType: string;
productClassId: number; productClassId: number;
@ -14,9 +15,32 @@ interface LayoutFurniImageViewProps
export const LayoutFurniImageView: FC<LayoutFurniImageViewProps> = props => export const LayoutFurniImageView: FC<LayoutFurniImageViewProps> = props =>
{ {
const { productType = 's', productClassId = -1, direction = 0, extraData = '', scale = 1 } = props; const { productType = 's', productClassId = -1, direction = 2, extraData = '', scale = 1, style = {}, ...rest } = props;
const [ imageElement, setImageElement ] = useState<HTMLImageElement>(null); const [ imageElement, setImageElement ] = useState<HTMLImageElement>(null);
const getStyle = useMemo(() =>
{
let newStyle: CSSProperties = {};
if(imageElement?.src?.length)
{
newStyle.backgroundImage = `url('${ imageElement.src }')`;
newStyle.width = imageElement.width;
newStyle.height = imageElement.height;
}
if(scale !== 1)
{
newStyle.transform = `scale(${ scale })`;
if(!(scale % 1)) newStyle.imageRendering = 'pixelated';
}
if(Object.keys(style).length) newStyle = { ...newStyle, ...style };
return newStyle;
}, [ imageElement, scale, style ]);
const buildImage = useCallback(() => const buildImage = useCallback(() =>
{ {
let imageResult: ImageResult = null; let imageResult: ImageResult = null;
@ -59,7 +83,5 @@ export const LayoutFurniImageView: FC<LayoutFurniImageViewProps> = props =>
if(!imageElement) return null; if(!imageElement) return null;
const imageUrl = `url('${ imageElement.src }')`; return <Base classNames={ [ 'furni-image' ] } style={ getStyle } { ...rest } />;
return <Base classNames={ [ 'furni-image', `scale-${ scale }` ] } style={ { backgroundImage: imageUrl, width: imageElement.width, height: imageElement.height } } />;
} }

View File

@ -1,13 +1,14 @@
import { PetCustomPart, PetFigureData, TextureUtils, Vector3d } from '@nitrots/nitro-renderer'; import { PetCustomPart, PetFigureData, TextureUtils, Vector3d } from '@nitrots/nitro-renderer';
import { FC, useEffect, useRef, useState } from 'react'; import { CSSProperties, FC, useEffect, useMemo, useRef, useState } from 'react';
import { GetRoomEngine } from '../../api'; import { GetRoomEngine } from '../../api';
import { Base, BaseProps } from '../Base';
interface LayoutPetImageViewProps interface LayoutPetImageViewProps extends BaseProps<HTMLDivElement>
{ {
figure?: string; figure?: string;
typeId?: number; typeId?: number;
paletteId?: number; paletteId?: number;
color?: number; petColor?: number;
customParts?: PetCustomPart[]; customParts?: PetCustomPart[];
posture?: string; posture?: string;
headOnly?: boolean; headOnly?: boolean;
@ -17,17 +18,35 @@ interface LayoutPetImageViewProps
export const LayoutPetImageView: FC<LayoutPetImageViewProps> = props => export const LayoutPetImageView: FC<LayoutPetImageViewProps> = props =>
{ {
const { figure = '', typeId = -1, paletteId = -1, color = 0xFFFFFF, customParts = [], posture = 'std', headOnly = false, direction = 0, scale = 1 } = props; const { figure = '', typeId = -1, paletteId = -1, petColor = 0xFFFFFF, customParts = [], posture = 'std', headOnly = false, direction = 0, scale = 1, style = {}, ...rest } = props;
const [ petUrl, setPetUrl ] = useState<string>(null); const [ petUrl, setPetUrl ] = useState<string>(null);
const isDisposed = useRef(false); const isDisposed = useRef(false);
const getStyle = useMemo(() =>
{
let newStyle: CSSProperties = {};
if(petUrl && petUrl.length) newStyle.backgroundImage = `url(${ petUrl })`;
if(scale !== 1)
{
newStyle.transform = `scale(${ scale })`;
if(!(scale % 1)) newStyle.imageRendering = 'pixelated';
}
if(Object.keys(style).length) newStyle = { ...newStyle, ...style };
return newStyle;
}, [ petUrl, scale, style ]);
useEffect(() => useEffect(() =>
{ {
let url = null; let url = null;
let petTypeId = typeId; let petTypeId = typeId;
let petPaletteId = paletteId; let petPaletteId = paletteId;
let petColor = color; let petColor1 = petColor;
let petCustomParts = customParts; let petCustomParts = customParts;
let petHeadOnly = headOnly; let petHeadOnly = headOnly;
@ -37,13 +56,13 @@ export const LayoutPetImageView: FC<LayoutPetImageViewProps> = props =>
petTypeId = petFigureData.typeId; petTypeId = petFigureData.typeId;
petPaletteId = petFigureData.paletteId; petPaletteId = petFigureData.paletteId;
petColor = petFigureData.color; petColor1 = petFigureData.color;
petCustomParts = petFigureData.customParts; petCustomParts = petFigureData.customParts;
} }
if(petTypeId === 16) petHeadOnly = false; if(petTypeId === 16) petHeadOnly = false;
const imageResult = GetRoomEngine().getRoomObjectPetImage(petTypeId, petPaletteId, petColor, new Vector3d((direction * 45)), 64, { const imageResult = GetRoomEngine().getRoomObjectPetImage(petTypeId, petPaletteId, petColor1, new Vector3d((direction * 45)), 64, {
imageReady: (id, texture, image) => imageReady: (id, texture, image) =>
{ {
if(isDisposed.current) return; if(isDisposed.current) return;
@ -65,7 +84,7 @@ export const LayoutPetImageView: FC<LayoutPetImageViewProps> = props =>
} }
}, [ figure, typeId, paletteId, color, customParts, posture, headOnly, direction ]); }, [ figure, typeId, paletteId, petColor, customParts, posture, headOnly, direction ]);
useEffect(() => useEffect(() =>
{ {
@ -78,6 +97,6 @@ export const LayoutPetImageView: FC<LayoutPetImageViewProps> = props =>
}, []); }, []);
const url = `url('${ petUrl }')`; const url = `url('${ petUrl }')`;
return <div className={ 'pet-image scale-' + scale.toString().replace('.', '-') } style={ (petUrl && url.length) ? { backgroundImage: url } : {} }></div>; return <Base classNames={ [ 'pet-image' ] } style={ getStyle } { ...rest } />;
} }

View File

@ -7,15 +7,20 @@
border-radius: $border-radius; border-radius: $border-radius;
box-shadow: 0 0 0 1.5px $white; box-shadow: 0 0 0 1.5px $white;
border: 2px solid #921911; border: 2px solid #921911;
background: repeating-linear-gradient(rgba(245,80,65,1), rgba(245,80,65,1) 50%, rgba(194,48,39,1) 50%, rgba(194,48,39,1) 100%); background: repeating-linear-gradient(
rgba(245, 80, 65, 1),
rgba(245, 80, 65, 1) 50%,
rgba(194, 48, 39, 1) 50%,
rgba(194, 48, 39, 1) 100%
);
cursor: pointer; cursor: pointer;
line-height: 1; line-height: 1;
padding: 1px 3px; padding: 1px 3px;
&:hover { &:hover {
filter: brightness(1.2); filter: brightness(1.2);
} }
&:active { &:active {
filter: brightness(0.8); filter: brightness(0.8);
} }
@ -28,42 +33,41 @@
width: 320px; width: 320px;
height: 320px; height: 320px;
} }
.camera-canvas { .camera-canvas {
position: relative; position: relative;
width: 340px; width: 340px;
height: 462px; height: 462px;
background-image: url('../../assets/images/room-widgets/camera-widget/camera-spritesheet.png'); background-image: url("../../assets/images/room-widgets/camera-widget/camera-spritesheet.png");
background-position: -1px -1px; background-position: -1px -1px;
z-index: 2; z-index: 2;
.camera-button { .camera-button {
width: 94px; width: 94px;
height: 94px; height: 94px;
cursor: pointer; cursor: pointer;
margin-top: 362px; margin-top: 362px;
background-image: url('../../assets/images/room-widgets/camera-widget/camera-spritesheet.png'); background-image: url("../../assets/images/room-widgets/camera-widget/camera-spritesheet.png");
background-position: -343px -321px; background-position: -343px -321px;
&:hover { &:hover {
background-position: -535px -321px; background-position: -535px -321px;
} }
&:active { &:active {
background-position: -439px -321px; background-position: -439px -321px;
} }
} }
.camera-view-finder { .camera-view-finder {
background-image: url('../../assets/images/room-widgets/camera-widget/camera-spritesheet.png'); background-image: url("../../assets/images/room-widgets/camera-widget/camera-spritesheet.png");
background-position: -343px -1px; background-position: -343px -1px;
} }
.camera-frame { .camera-frame {
.camera-frame-preview-actions { .camera-frame-preview-actions {
background: rgba(0, 0, 0, .5); background: rgba(0, 0, 0, 0.5);
} }
} }
} }
@ -80,6 +84,8 @@
width: 56px; width: 56px;
height: 56px; height: 56px;
border: 1px solid black; border: 1px solid black;
object-fit: contain;
image-rendering: initial;
} }
} }
} }
@ -87,7 +93,7 @@
.nitro-camera-editor { .nitro-camera-editor {
width: $camera-editor-width; width: $camera-editor-width;
height: $camera-editor-height; height: $camera-editor-height;
.picture-preview { .picture-preview {
width: 320px; width: 320px;
height: 320px; height: 320px;
@ -99,7 +105,6 @@
} }
.effect-thumbnail-image { .effect-thumbnail-image {
img { img {
width: 50px; width: 50px;
height: 50px; height: 50px;

View File

@ -1,6 +1,6 @@
import { IRoomCameraWidgetEffect, IRoomCameraWidgetSelectedEffect } from '@nitrots/nitro-renderer'; import { IRoomCameraWidgetEffect, IRoomCameraWidgetSelectedEffect } from '@nitrots/nitro-renderer';
import { FC } from 'react'; import { FC } from 'react';
import { AutoGrid } from '../../../../../common/AutoGrid'; import { Grid } from '../../../../../common';
import { CameraPictureThumbnail } from '../../../common/CameraPictureThumbnail'; import { CameraPictureThumbnail } from '../../../common/CameraPictureThumbnail';
import { CameraWidgetEffectListItemView } from './CameraWidgetEffectListItemView'; import { CameraWidgetEffectListItemView } from './CameraWidgetEffectListItemView';
@ -18,7 +18,7 @@ export const CameraWidgetEffectListView: FC<CameraWidgetEffectListViewProps> = p
const { myLevel = 0, selectedEffects = [], effects = [], thumbnails = [], processAction = null } = props; const { myLevel = 0, selectedEffects = [], effects = [], thumbnails = [], processAction = null } = props;
return ( return (
<AutoGrid columnCount={ 2 } columnMinHeight={ 60 }> <Grid columnCount={ 3 } overflow="auto">
{ effects && (effects.length > 0) && effects.map((effect, index) => { effects && (effects.length > 0) && effects.map((effect, index) =>
{ {
const thumbnailUrl = (thumbnails.find(thumbnail => (thumbnail.effectName === effect.name))); const thumbnailUrl = (thumbnails.find(thumbnail => (thumbnail.effectName === effect.name)));
@ -26,6 +26,6 @@ export const CameraWidgetEffectListView: FC<CameraWidgetEffectListViewProps> = p
return <CameraWidgetEffectListItemView key={ index } effect={ effect } thumbnailUrl={ ((thumbnailUrl && thumbnailUrl.thumbnailUrl) || null) } isActive={ isActive } isLocked={ (effect.minLevel > myLevel) } selectEffect={ () => processAction('select_effect', effect.name) } removeEffect={ () => processAction('remove_effect', effect.name) } /> return <CameraWidgetEffectListItemView key={ index } effect={ effect } thumbnailUrl={ ((thumbnailUrl && thumbnailUrl.thumbnailUrl) || null) } isActive={ isActive } isLocked={ (effect.minLevel > myLevel) } selectEffect={ () => processAction('select_effect', effect.name) } removeEffect={ () => processAction('remove_effect', effect.name) } />
}) } }) }
</AutoGrid> </Grid>
); );
} }

View File

@ -109,7 +109,7 @@ export const RoomColorView: FC<{}> = props =>
{ {
if(!roomSession) return; if(!roomSession) return;
const canvas = GetRoomEngine().getRoomInstanceRenderingCanvas(GetRoomEngine().activeRoomId, 1); const canvas = GetRoomEngine().getRoomInstanceRenderingCanvas(roomSession.roomId, 1);
if(!canvas) return; if(!canvas) return;

View File

@ -88,9 +88,7 @@ export const RoomView: FC<{}> = props =>
const roomEngine = GetRoomEngine(); const roomEngine = GetRoomEngine();
const roomId = roomSession.roomId; const roomId = roomSession.roomId;
const canvasId = 1; const canvasId = 1;
const displayObject = roomEngine.getRoomInstanceDisplay(roomId, canvasId, (window.innerWidth * window.devicePixelRatio), (window.innerHeight * window.devicePixelRatio), RoomGeometry.SCALE_ZOOMED_IN); const displayObject = roomEngine.getRoomInstanceDisplay(roomId, canvasId, window.innerWidth, window.innerHeight, RoomGeometry.SCALE_ZOOMED_IN);
if((window.devicePixelRatio !== 1) && ((window.devicePixelRatio % 1) === 0)) roomEngine.setRoomInstanceRenderingCanvasScale(roomId, canvasId, window.devicePixelRatio);
if(!displayObject) return; if(!displayObject) return;
@ -141,25 +139,20 @@ export const RoomView: FC<{}> = props =>
canvas.ontouchend = event => DispatchTouchEvent(event); canvas.ontouchend = event => DispatchTouchEvent(event);
canvas.ontouchcancel = event => DispatchTouchEvent(event); canvas.ontouchcancel = event => DispatchTouchEvent(event);
if(window.devicePixelRatio !== 1) canvas.style.width = `${ Math.floor(window.innerWidth) }px`;
{ canvas.style.height = `${ Math.floor(window.innerHeight) }px`;
let scaleValue = (1 / window.devicePixelRatio);
canvas.style.transform = `scale(${ scaleValue })`;
canvas.style.transformOrigin = 'top left';
canvas.style.width = `${ (100 * window.devicePixelRatio) }%`;
canvas.style.height = `${ (100 * window.devicePixelRatio) }%`;
}
const resize = (event: UIEvent) => const resize = (event: UIEvent) =>
{ {
canvas.style.width = `${ Math.floor(window.innerWidth) }px`;
canvas.style.height = `${ Math.floor(window.innerHeight) }px`;
const nitroInstance = GetNitroInstance(); const nitroInstance = GetNitroInstance();
const width = (window.innerWidth * window.devicePixelRatio);
const height = (window.innerHeight * window.devicePixelRatio);
nitroInstance.renderer.resize(width, height); nitroInstance.renderer.resolution = window.devicePixelRatio;
nitroInstance.renderer.resize(window.innerWidth, window.innerHeight);
InitializeRoomInstanceRenderingCanvas(width, height, 1); InitializeRoomInstanceRenderingCanvas(window.innerWidth, window.innerHeight, 1);
nitroInstance.render(); nitroInstance.render();
} }
@ -180,8 +173,7 @@ export const RoomView: FC<{}> = props =>
return ( return (
<RoomContextProvider value={ { roomSession, eventDispatcher: (widgetHandler && widgetHandler.eventDispatcher), widgetHandler } }> <RoomContextProvider value={ { roomSession, eventDispatcher: (widgetHandler && widgetHandler.eventDispatcher), widgetHandler } }>
<Base fit className={ (!roomSession && 'd-none') }> <Base fit innerRef={ elementRef } className={ (!roomSession && 'd-none') }>
<Base innerRef={ elementRef } />
{ (roomSession && widgetHandler) && { (roomSession && widgetHandler) &&
<> <>
<RoomColorView /> <RoomColorView />

View File

@ -69,7 +69,7 @@ export const AvatarInfoUseProductConfirmView: FC<AvatarInfoUseProductConfirmView
} }
} }
return <LayoutPetImageView typeId={ petFigureData.typeId } paletteId={ paletteId } color={ petFigureData.color } customParts={ petFigureData.customParts } direction={ 2 } /> return <LayoutPetImageView typeId={ petFigureData.typeId } paletteId={ paletteId } petColor={ petFigureData.color } customParts={ petFigureData.customParts } direction={ 2 } />
} }
case FurniCategory.PET_CUSTOM_PART: { case FurniCategory.PET_CUSTOM_PART: {
if(customParts.length < 4) return null; if(customParts.length < 4) return null;
@ -96,7 +96,7 @@ export const AvatarInfoUseProductConfirmView: FC<AvatarInfoUseProductConfirmView
_local_10++; _local_10++;
} }
return <LayoutPetImageView typeId={ petFigureData.typeId } paletteId={ petFigureData.paletteId } color={ petFigureData.color } customParts={ newCustomParts } direction={ 2 } />; return <LayoutPetImageView typeId={ petFigureData.typeId } paletteId={ petFigureData.paletteId } petColor={ petFigureData.color } customParts={ newCustomParts } direction={ 2 } />;
} }
case FurniCategory.PET_CUSTOM_PART_SHAMPOO: { case FurniCategory.PET_CUSTOM_PART_SHAMPOO: {
if(customParts.length < 3) return null; if(customParts.length < 3) return null;
@ -122,7 +122,7 @@ export const AvatarInfoUseProductConfirmView: FC<AvatarInfoUseProductConfirmView
_local_10++; _local_10++;
} }
return <LayoutPetImageView typeId={ petFigureData.typeId } paletteId={ petFigureData.paletteId } color={ petFigureData.color } customParts={ newCustomParts } direction={ 2 } />; return <LayoutPetImageView typeId={ petFigureData.typeId } paletteId={ petFigureData.paletteId } petColor={ petFigureData.color } customParts={ newCustomParts } direction={ 2 } />;
} }
case FurniCategory.PET_SADDLE: { case FurniCategory.PET_SADDLE: {
if(customParts.length < 4) return null; if(customParts.length < 4) return null;
@ -150,7 +150,7 @@ export const AvatarInfoUseProductConfirmView: FC<AvatarInfoUseProductConfirmView
} }
} }
return <LayoutPetImageView typeId={ petFigureData.typeId } paletteId={ petFigureData.paletteId } color={ petFigureData.color } customParts={ newCustomParts } direction={ 2 } />; return <LayoutPetImageView typeId={ petFigureData.typeId } paletteId={ petFigureData.paletteId } petColor={ petFigureData.color } customParts={ newCustomParts } direction={ 2 } />;
} }
case FurniCategory.MONSTERPLANT_REBREED: case FurniCategory.MONSTERPLANT_REBREED:
case FurniCategory.MONSTERPLANT_REVIVAL: case FurniCategory.MONSTERPLANT_REVIVAL:
@ -172,7 +172,7 @@ export const AvatarInfoUseProductConfirmView: FC<AvatarInfoUseProductConfirmView
} }
} }
return <LayoutPetImageView typeId={ petFigureData.typeId } paletteId={ petFigureData.paletteId } color={ petFigureData.color } customParts={ petFigureData.customParts } posture={ posture } direction={ 2 } />; return <LayoutPetImageView typeId={ petFigureData.typeId } paletteId={ petFigureData.paletteId } petColor={ petFigureData.color } customParts={ petFigureData.customParts } posture={ posture } direction={ 2 } />;
} }
} }
}, [ petData, furniData, roomSession ]); }, [ petData, furniData, roomSession ]);

View File

@ -697,15 +697,15 @@
.user-image { .user-image {
position: absolute; position: absolute;
top: -48px; top: -15px;
left: -32.5px; left: -9.25px;
width: 90px; width: 45px;
height: 130px; height: 65px;
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center; background-position: center;
transform: scale(0.5); transform: scale(0.5);
overflow: hidden; overflow: hidden;
image-rendering: -webkit-optimize-contrast; image-rendering: initial;
} }
} }

View File

@ -145,7 +145,7 @@ export const ChatWidgetView: FC<{}> = props =>
{ {
if(!chatMessages.length || (event.roomId !== roomSession.roomId)) return; if(!chatMessages.length || (event.roomId !== roomSession.roomId)) return;
const offsetX = (event.offsetX / window.devicePixelRatio); const offsetX = event.offsetX;
chatMessages.forEach(chat => (chat.elementRef && (chat.left += offsetX))); chatMessages.forEach(chat => (chat.elementRef && (chat.left += offsetX)));
}, [ roomSession, chatMessages ]); }, [ roomSession, chatMessages ]);
@ -200,7 +200,7 @@ export const ChatWidgetView: FC<{}> = props =>
if(!elementRef || !elementRef.current) return; if(!elementRef || !elementRef.current) return;
const currentHeight = elementRef.current.offsetHeight; const currentHeight = elementRef.current.offsetHeight;
const newHeight = (document.body.offsetHeight * GetConfiguration<number>('chat.viewer.height.percentage')); const newHeight = Math.round(document.body.offsetHeight * GetConfiguration<number>('chat.viewer.height.percentage'));
elementRef.current.style.height = `${ newHeight }px`; elementRef.current.style.height = `${ newHeight }px`;
@ -208,17 +208,7 @@ export const ChatWidgetView: FC<{}> = props =>
{ {
if(prevValue) if(prevValue)
{ {
prevValue.forEach(chat => prevValue.forEach(chat => (chat.top -= (currentHeight - newHeight)));
{
if(chat.skipMovement)
{
chat.skipMovement = false;
return;
}
chat.top -= (currentHeight - newHeight);
});
} }
return prevValue; return prevValue;

View File

@ -27,9 +27,10 @@ export const RoomToolsWidgetView: FC<{}> = props =>
case 'zoom': case 'zoom':
setIsZoomedIn(prevValue => setIsZoomedIn(prevValue =>
{ {
let scale = ((window.devicePixelRatio !== 1) && ((window.devicePixelRatio % 1) === 0)) ? window.devicePixelRatio : 1; let scale = GetRoomEngine().getRoomInstanceRenderingCanvasScale(roomSession.roomId, 1);
if(!prevValue) scale /= 2; if(!prevValue) scale /= 2;
else scale *= 2;
GetRoomEngine().setRoomInstanceRenderingCanvasScale(roomSession.roomId, 1, scale); GetRoomEngine().setRoomInstanceRenderingCanvasScale(roomSession.roomId, 1, scale);

View File

@ -78,7 +78,7 @@ export const ToolbarView: FC<{ isInRoom: boolean }> = props =>
<Flex gap={ 2 } alignItems="center"> <Flex gap={ 2 } alignItems="center">
<Flex alignItems="center" gap={ 2 }> <Flex alignItems="center" gap={ 2 }>
<Flex center pointer className={ 'navigation-item item-avatar ' + (isMeExpanded ? 'active ' : '') } onClick={ event => setMeExpanded(!isMeExpanded) }> <Flex center pointer className={ 'navigation-item item-avatar ' + (isMeExpanded ? 'active ' : '') } onClick={ event => setMeExpanded(!isMeExpanded) }>
<LayoutAvatarImageView figure={ userFigure } direction={ 2 } /> <LayoutAvatarImageView figure={ userFigure } direction={ 2 } position="absolute" />
{ (getTotalUnseen > 0) && { (getTotalUnseen > 0) &&
<LayoutItemCountView count={ getTotalUnseen } /> } <LayoutItemCountView count={ getTotalUnseen } /> }
</Flex> </Flex>

View File

@ -1,5 +1,4 @@
@import "./assets/styles";
@import './assets/styles';
html, html,
body { body {
@ -8,10 +7,13 @@ body {
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
user-select: none; user-select: none;
image-rendering: pixelated;
image-rendering: -moz-crisp-edges;
scrollbar-width: thin; scrollbar-width: thin;
.image-rendering-pixelated {
image-rendering: pixelated;
image-rendering: -moz-crisp-edges;
}
* { * {
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
} }
@ -21,4 +23,4 @@ img {
object-fit: none; object-fit: none;
} }
@import './App'; @import "./App";