🚶 Floorplan & structure CSS

This commit is contained in:
duckietm 2025-03-19 10:54:39 +01:00
parent d487102236
commit 141d4bc68a
22 changed files with 1229 additions and 3423 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -1,856 +0,0 @@
.bubble-container {
transition: top 0.2s ease 0s;
.chat-bubble {
border-image-slice: 17 6 6 29 fill;
border-image-width: 17px 6px 6px 29px;
border-image-outset: 2px 0px 0px 0px;
border-image-repeat: repeat repeat;
&.type-0 {
// normal
.message {
font-weight: 400;
}
}
&.type-1 {
// whisper
.message {
font-weight: 400;
font-style: italic;
color: #595959;
}
}
&.type-2 {
// shout
.message {
font-weight: 700;
}
}
&.bubble-0 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_0_transparent.png');
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_0_1_33_34_pointer.png');
bottom: -5px;
}
}
&.bubble-1 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_1.png');
border-image-slice: 18 6 6 29 fill;
border-image-width: 18px 6px 6px 29px;
border-image-outset: 3px 0px 0px 0px;
.user-container {
display: none;
}
.username {
display: none;
}
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_0_1_33_34_pointer.png');
}
}
&.bubble-2,
&.bubble-31 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_2.png');
.user-container {
display: none;
}
.username {
color: rgba($white, 1);
}
.message {
color: rgba($white, 1) !important;
}
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_2_31_pointer.png');
height: 7px;
}
}
&.bubble-3 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_3.png');
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_3_pointer.png');
}
}
&.bubble-4 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_4.png');
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_4_pointer.png');
}
}
&.bubble-5 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_5.png');
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_5_pointer.png');
}
}
&.bubble-6 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_6.png');
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_6_pointer.png');
}
}
&.bubble-7 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_7.png');
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_7_pointer.png');
}
}
&.bubble-8 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_8.png');
border-image-slice: 20 6 6 27 fill;
border-image-width: 20px 6px 6px 27px;
border-image-outset: 5px 0px 0px 0px;
.chat-content {
color: #fff;
}
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_8_pointer.png');
}
}
&.bubble-9 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_9.png');
border-image-slice: 17 18 12 19 fill;
border-image-width: 17px 18px 12px 19px;
border-image-outset: 7px 7px 0px 9px;
.chat-content {
margin-left: 20px;
}
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_9_pointer.png');
width: 7px;
height: 10px;
bottom: -6px;
}
}
&.bubble-10 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_10.png');
border-image-slice: 29 18 8 37 fill;
border-image-width: 29px 18px 8px 37px;
border-image-outset: 12px 7px 1px 5px;
.chat-content {
margin-left: 24px;
color: #fff;
}
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_10_pointer.png');
width: 7px;
height: 8px;
bottom: -3px;
}
}
&.bubble-11 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_11.png');
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_11_pointer.png');
}
}
&.bubble-12 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_12.png');
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_12_pointer.png');
}
}
&.bubble-13 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_13.png');
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_13_pointer.png');
}
}
&.bubble-14 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_14.png');
.chat-content {
color: #fff;
}
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_14_pointer.png');
}
}
&.bubble-15 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_15.png');
.chat-content {
color: #fff;
}
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_15_pointer.png');
}
}
&.bubble-16 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_16.png');
border-image-slice: 13 6 10 31 fill;
border-image-width: 13px 6px 10px 31px;
border-image-outset: 6px 0px 0px 0px;
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_16_pointer.png');
height: 8px;
}
}
&.bubble-17 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_17.png');
border-image-slice: 24 6 8 35 fill;
border-image-width: 24px 6px 8px 35px;
border-image-outset: 9px 0px 2px 5px;
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_17_pointer.png');
}
}
&.bubble-18 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_18.png');
border-image-slice: 7 16 8 16 fill;
border-image-width: 7px 16px 8px 16px;
border-image-outset: 3px 10px 2px 11px;
.chat-content {
margin-left: 20px;
}
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_18_pointer.png');
height: 8px;
}
}
&.bubble-19 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_19.png');
border-image-slice: 17 6 9 19 fill;
border-image-width: 17px 6px 9px 19px;
border-image-outset: 5px 0px 0px 8px;
.chat-content {
margin-left: 20px;
}
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_19_20_pointer.png');
}
}
&.bubble-20 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_20.png');
border-image-slice: 18 6 8 19 fill;
border-image-width: 18px 6px 8px 19px;
border-image-outset: 5px 0px 0px 8px;
.chat-content {
margin-left: 20px;
}
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_19_20_pointer.png');
}
}
&.bubble-21 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_21.png');
border-image-slice: 20 6 12 24 fill;
border-image-width: 20px 6px 12px 24px;
border-image-outset: 13px 2px 1px 3px;
.chat-content {
margin-left: 20px;
}
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_21_pointer.png');
bottom: -4px;
}
}
&.bubble-22 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_22.png');
border-image-slice: 18 19 11 33 fill;
border-image-width: 18px 19px 11px 33px;
border-image-outset: 7px 1px 1px 5px;
.chat-content {
margin-left: 20px;
}
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_22_pointer.png');
}
}
&.bubble-23 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_23.png');
border-image-slice: 16 6 7 32 fill;
border-image-width: 16px 6px 7px 32px;
border-image-outset: 5px 0px 0px 3px;
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_23_37_pointer.png');
}
}
&.bubble-24 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_24.png');
border-image-slice: 23 8 6 40 fill;
border-image-width: 23px 8px 6px 40px;
border-image-outset: 6px 0px 0px 6px;
.chat-content {
margin-left: 30px;
color: #fff;
}
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_24_pointer.png');
bottom: -4px;
}
}
&.bubble-25 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_25.png');
border-image-slice: 10 13 8 28 fill;
border-image-width: 10px 13px 8px 28px;
border-image-outset: 6px 3px 2px 0px;
.chat-content {
color: #fff;
}
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_25_pointer.png');
height: 9px;
bottom: -7px;
}
}
&.bubble-26 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_26.png');
border-image-slice: 16 9 8 29 fill;
border-image-width: 16px 9px 8px 29px;
border-image-outset: 2px 2px 2px 0px;
.chat-content {
color: #c59432;
text-shadow: 1px 1px rgba(0, 0, 0, 0.3);
}
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_26_pointer.png');
height: 10px;
bottom: -6px;
}
}
&.bubble-27 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_27.png');
border-image-slice: 25 6 5 36 fill;
border-image-width: 25px 6px 5px 36px;
border-image-outset: 8px 0px 0px 5px;
.chat-content {
margin-left: 30px;
color: #fff;
}
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_27_pointer.png');
}
}
&.bubble-28 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_28.png');
border-image-slice: 16 7 7 27 fill;
border-image-width: 16px 7px 7px 27px;
border-image-outset: 3px 0px 0px 0px;
.chat-content {
margin-left: 25px;
}
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_28_pointer.png');
}
}
&.bubble-29 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_29.png');
border-image-slice: 10 7 15 31 fill;
border-image-width: 10px 7px 15px 31px;
border-image-outset: 2px 0px 0px 1px;
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_29_pointer.png');
bottom: -4px;
}
}
&.bubble-30 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_30.png');
.user-container {
display: none;
}
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_30_pointer.png');
height: 7px;
}
}
&.bubble-32 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_32.png');
border-image-slice: 15 7 7 30 fill;
border-image-width: 15px 7px 7px 30px;
border-image-outset: 2px 0px 0px 0px;
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_32_pointer.png');
}
}
&.bubble-33 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_33_34.png');
border-image-slice: 7 6 6 39 fill;
border-image-width: 7px 6px 6px 39px;
border-image-outset: 2px 0px 0px 0px;
.user-container {
display: none;
}
.chat-content {
margin-left: 35px;
}
&::before {
content: ' ';
position: absolute;
width: 19px;
height: 19px;
left: 9px;
top: 2px;
background: url('@/assets/images/chat/chatbubbles/bubble_33_extra.png');
}
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_0_1_33_34_pointer.png');
}
}
&.bubble-34 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_33_34.png');
border-image-slice: 7 6 6 39 fill;
border-image-width: 7px 6px 6px 39px;
border-image-outset: 2px 0px 0px 0px;
&.type-1 {
.message {
font-style: unset;
color: inherit;
}
}
.user-container {
display: none;
}
.username {
display: none;
}
.chat-content {
margin-left: 35px;
}
&::before {
content: ' ';
position: absolute;
width: 19px;
height: 19px;
left: 9px;
top: 2px;
background: url('@/assets/images/chat/chatbubbles/bubble_34_extra.png');
}
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_0_1_33_34_pointer.png');
}
}
&.bubble-35 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_35.png');
border-image-slice: 19 6 5 29 fill;
border-image-width: 19px 6px 5px 29px;
border-image-outset: 4px 0px 0px 0px;
.user-container {
display: none;
}
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_35_pointer.png');
}
}
&.bubble-36 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_36.png');
border-image-slice: 17 7 5 30 fill;
border-image-width: 17px 7px 5px 30px;
border-image-outset: 2px 0px 0px 0px;
.user-container {
display: none;
}
&::before {
content: ' ';
position: absolute;
width: 13px;
height: 18px;
left: 5px;
top: 2px;
background: url('@/assets/images/chat/chatbubbles/bubble_36_extra.png');
}
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_36_pointer.png');
}
}
&.bubble-37 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_37.png');
border-image-slice: 16 6 7 32 fill;
border-image-width: 16px 6px 7px 32px;
border-image-outset: 5px 0px 0px 3px;
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_23_37_pointer.png');
}
}
&.bubble-38 {
border-image-source: url('@/assets/images/chat/chatbubbles/bubble_38.png');
border-image-slice: 17 7 5 30 fill;
border-image-width: 17px 7px 5px 30px;
border-image-outset: 2px 0px 0px 0px;
.user-container {
display: none;
}
&::before {
content: ' ';
position: absolute;
width: 19px;
height: 19px;
left: 3px;
top: 2px;
background: url('@/assets/images/chat/chatbubbles/bubble_38_extra.png');
}
.pointer {
background: url('@/assets/images/chat/chatbubbles/bubble_38_pointer.png');
}
}
.user-container {
z-index: 3;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
max-height: 24px;
overflow: hidden;
.user-image {
position: absolute;
top: -15px;
left: -9.25px;
width: 45px;
height: 65px;
background-repeat: no-repeat;
background-position: center;
transform: scale(0.5);
overflow: hidden;
image-rendering: initial;
}
}
.chat-content {
padding: 5px 6px 5px 4px;
margin-left: 27px;
line-height: 1;
color: $black;
min-height: 25px;
}
}
}
.chat-bubble-icon {
background-repeat: no-repeat;
background-position: center;
&.bubble-0 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_0.png');
}
&.bubble-1 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_1.png');
height: 25px;
}
&.bubble-2,
&.bubble-31 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_2.png');
}
&.bubble-3 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_3.png');
}
&.bubble-4 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_4.png');
}
&.bubble-5 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_5.png');
}
&.bubble-6 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_6.png');
}
&.bubble-7 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_7.png');
}
&.bubble-8 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_8.png');
}
&.bubble-9 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_9.png');
}
&.bubble-10 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_10.png');
}
&.bubble-11 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_11.png');
}
&.bubble-12 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_12.png');
}
&.bubble-13 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_13.png');
}
&.bubble-14 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_14.png');
}
&.bubble-15 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_15.png');
}
&.bubble-16 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_16.png');
}
&.bubble-17 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_17.png');
}
&.bubble-18 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_18.png');
}
&.bubble-19 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_19.png');
}
&.bubble-20 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_20.png');
}
&.bubble-21 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_21.png');
}
&.bubble-22 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_22.png');
}
&.bubble-23 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_23.png');
}
&.bubble-24 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_24.png');
}
&.bubble-25 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_25.png');
}
&.bubble-26 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_26.png');
}
&.bubble-27 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_27.png');
}
&.bubble-28 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_28.png');
}
&.bubble-29 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_29.png');
}
&.bubble-30 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_30.png');
}
&.bubble-32 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_32.png');
}
&.bubble-33 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_33_34.png');
&::before {
content: ' ';
position: absolute;
width: 19px;
height: 19px;
left: 11px;
top: 10px;
background: url('@/assets/images/chat/chatbubbles/bubble_33_extra.png');
}
}
&.bubble-34 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_33_34.png');
&::before {
content: ' ';
position: absolute;
width: 19px;
height: 19px;
left: 11px;
top: 10px;
background: url('@/assets/images/chat/chatbubbles/bubble_34_extra.png');
}
}
&.bubble-35 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_35.png');
}
&.bubble-36 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_36.png');
&::before {
content: ' ';
position: absolute;
width: 13px;
height: 18px;
left: 13px;
top: 10px;
background: url('@/assets/images/chat/chatbubbles/bubble_36_extra.png');
}
}
&.bubble-37 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_35.png');
}
&.bubble-38 {
background-image: url('@/assets/images/chat/chatbubbles/bubble_38.png');
&::before {
content: ' ';
position: absolute;
width: 19px;
height: 19px;
left: 11px;
top: 10px;
background: url('@/assets/images/chat/chatbubbles/bubble_38_extra.png');
}
}
}

21
src/common/Slider.tsx Normal file
View File

@ -0,0 +1,21 @@
import { FC } from 'react';
import ReactSlider, { ReactSliderProps } from 'react-slider';
import { Button } from './Button';
import { Flex } from './Flex';
import { FaAngleLeft, FaAngleRight } from 'react-icons/fa';
export interface SliderProps extends ReactSliderProps
{
disabledButton?: boolean;
}
export const Slider: FC<SliderProps> = props =>
{
const { disabledButton, max, min, value, onChange, ...rest } = props;
return <Flex fullWidth gap={ 1 }>
{ !disabledButton && <Button disabled={ min >= value } onClick={ () => onChange(min < value ? value - 1 : min, 0) }><FaAngleLeft /></Button> }
<ReactSlider className={ 'nitro-slider' } max={ max } min={ min } value={ value } onChange={ onChange } { ...rest } />
{ !disabledButton && <Button disabled={ max <= value } onClick={ () => onChange(max > value ? value + 1 : max, 0) }><FaAngleRight /></Button> }
</Flex>;
}

View File

@ -18,4 +18,5 @@ export * from './draggable-window';
export * from './layout';
export * from './layout/limited-edition';
export * from './types';
export * from "./Slider";
export * from './utils';

View File

@ -1,7 +1,7 @@
import { AddLinkEventTracker, FloorHeightMapEvent, ILinkEventTracker, RemoveLinkEventTracker, RoomEngineEvent, RoomVisualizationSettingsEvent, UpdateFloorPropertiesMessageComposer } from '@nitrots/nitro-renderer';
import { FC, useEffect, useState } from 'react';
import { LocalizeText, SendMessageComposer } from '../../api';
import { Button, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../common';
import { Button, ButtonGroup, Flex, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../common';
import { useMessageEvent, useNitroEvent } from '../../hooks';
import { FloorplanEditorContextProvider } from './FloorplanEditorContext';
import { FloorplanEditor } from './common/FloorplanEditor';
@ -43,7 +43,7 @@ export const FloorplanEditorView: FC<{}> = props =>
convertNumbersForSaving(visualizationSettings.thicknessFloor),
(visualizationSettings.wallHeight - 1)
));
};
}
const revertChanges = () =>
{
@ -138,23 +138,23 @@ export const FloorplanEditorView: FC<{}> = props =>
return (
<FloorplanEditorContextProvider value={ { originalFloorplanSettings: originalFloorplanSettings, setOriginalFloorplanSettings: setOriginalFloorplanSettings, visualizationSettings: visualizationSettings, setVisualizationSettings: setVisualizationSettings } }>
{ isVisible &&
<NitroCardView className="w-[760px] h-[500px]" theme="primary-slim" uniqueKey="floorpan-editor">
<NitroCardView uniqueKey="floorpan-editor" className="nitro-floorplan-editor" theme="primary-slim">
<NitroCardHeaderView headerText={ LocalizeText('floor.plan.editor.title') } onCloseClick={ () => setIsVisible(false) } />
<NitroCardContentView overflow="hidden">
<FloorplanOptionsView />
<FloorplanCanvasView overflow="hidden" />
<div className="flex justify-between">
<Flex justifyContent="between">
<Button onClick={ revertChanges }>{ LocalizeText('floor.plan.editor.reload') }</Button>
<div className="relative inline-flex align-middle">
<ButtonGroup>
<Button disabled={ true }>{ LocalizeText('floor.plan.editor.preview') }</Button>
<Button onClick={ event => setImportExportVisible(true) }>{ LocalizeText('floor.plan.editor.import.export') }</Button>
<Button onClick={ saveFloorChanges }>{ LocalizeText('floor.plan.editor.save') }</Button>
</div>
</div>
</ButtonGroup>
</Flex>
</NitroCardContentView>
</NitroCardView> }
{ importExportVisible &&
<FloorplanImportExportView onCloseClick={ () => setImportExportVisible(false) } /> }
</FloorplanEditorContextProvider>
);
};
}

View File

@ -2,10 +2,9 @@ import { ActionSettings } from './ActionSettings';
import { FloorAction, HEIGHT_SCHEME, MAX_NUM_TILE_PER_AXIS, TILE_SIZE } from './Constants';
import { imageBase64, spritesheet } from './FloorplanResource';
import { Tile } from './Tile';
import { getScreenPositionForTile } from './Utils';
import { getScreenPositionForTile, getTileFromScreenPosition } from './Utils';
export class FloorplanEditor
{
export class FloorplanEditor {
private static _INSTANCE: FloorplanEditor = null;
public static readonly TILE_BLOCKED = 'r_blocked';
@ -19,25 +18,24 @@ export class FloorplanEditor
private _lastUsedTile: { x: number, y: number };
private _renderer: CanvasRenderingContext2D;
private _actionSettings: ActionSettings;
private _image: HTMLImageElement;
private _zoomLevel: number = 1.0;
private _squareSelectMode: boolean = false;
private _selectionStart: { x: number, y: number } | null = null;
private _selectionEnd: { x: number, y: number } | null = null;
constructor()
{
constructor() {
const width = TILE_SIZE * MAX_NUM_TILE_PER_AXIS + 20;
const height = (TILE_SIZE * MAX_NUM_TILE_PER_AXIS) / 2 + 100;
const canvas = document.createElement('canvas');
canvas.height = height;
canvas.width = width;
canvas.style.touchAction = 'none';
canvas.oncontextmenu = (e) => { e.preventDefault(); }; // Added from old code
this._renderer = canvas.getContext('2d');
this._renderer = canvas.getContext('2d')!;
this._image = new Image();
this._image.src = imageBase64;
this._tilemap = [];
@ -49,69 +47,78 @@ export class FloorplanEditor
this._actionSettings = new ActionSettings();
}
public onPointerRelease(): void
{
this._isPointerDown = false;
public setSquareSelectMode(enabled: boolean): void {
this._squareSelectMode = enabled;
if (!enabled) {
this._selectionStart = null;
this._selectionEnd = null;
}
}
public onPointerDown(event: PointerEvent): void
{
if(event.button === 2) return;
public get squareSelectMode(): boolean {
return this._squareSelectMode;
}
const location = { x: event.offsetX, y: event.offsetY };
public onPointerRelease(): void {
this._isPointerDown = false;
if (this._squareSelectMode && this._selectionStart) {
this.finalizeSquareSelection();
}
}
public onPointerDown(event: PointerEvent): void {
if (this._squareSelectMode) {
event.preventDefault();
const location = { x: event.offsetX / this._zoomLevel, y: event.offsetY / this._zoomLevel };
const [tileX, tileY] = getTileFromScreenPosition(location.x, location.y);
const roundedX = Math.floor(tileX);
const roundedY = Math.floor(tileY);
this._selectionStart = { x: roundedX, y: roundedY };
this._selectionEnd = { x: roundedX, y: roundedY };
this._isPointerDown = true;
return;
}
if (event.button === 2) return;
const location = { x: event.offsetX / this._zoomLevel, y: event.offsetY / this._zoomLevel };
this._isPointerDown = true;
this.tileHitDetection(location, true);
}
public onPointerMove(event: PointerEvent): void
{
if(!this._isPointerDown) return;
const location = { x: event.offsetX, y: event.offsetY };
public onPointerMove(event: PointerEvent): void {
if (!this._isPointerDown) return;
const location = { x: event.offsetX / this._zoomLevel, y: event.offsetY / this._zoomLevel };
if (this._squareSelectMode && this._selectionStart) {
const [tileX, tileY] = getTileFromScreenPosition(location.x, location.y);
this._selectionEnd!.x = Math.floor(tileX);
this._selectionEnd!.y = Math.floor(tileY);
this.renderTiles();
return;
}
this.tileHitDetection(location, false);
}
private tileHitDetection(tempPoint: { x: number, y: number }, isClick: boolean = false): boolean
{
private tileHitDetection(tempPoint: { x: number, y: number }, isClick: boolean = false): boolean {
const mousePositionX = Math.floor(tempPoint.x);
const mousePositionY = Math.floor(tempPoint.y);
const width = TILE_SIZE;
const height = TILE_SIZE / 2;
for(let y = 0; y < this._tilemap.length; y++)
{
for(let x = 0; x < this.tilemap[y].length; x++)
{
const [ tileStartX, tileStartY ] = getScreenPositionForTile(x, y);
for (let y = 0; y < this._tilemap.length; y++) {
for (let x = 0; x < this._tilemap[y].length; x++) {
const [tileStartX, tileStartY] = getScreenPositionForTile(x, y);
const centreX = tileStartX + (width / 2);
const centreY = tileStartY + (height / 2);
const dx = Math.abs(mousePositionX - centreX);
const dy = Math.abs(mousePositionY - centreY);
const solution = (dx / (width * 0.5) + dy / (height * 0.5) <= 1);//todo: improve this
if(solution)
{
if(this._isPointerDown)
{
if(isClick)
{
const solution = (dx / (width * 0.5) + dy / (height * 0.5) <= 1);
if (solution) {
if (this._isPointerDown) {
if (isClick) {
this.onClick(x, y);
}
else if(this._lastUsedTile.x !== x || this._lastUsedTile.y !== y)
{
} else if (this._lastUsedTile.x !== x || this._lastUsedTile.y !== y) {
this._lastUsedTile.x = x;
this._lastUsedTile.y = y;
this.onClick(x, y);
}
}
return true;
}
@ -120,31 +127,25 @@ export class FloorplanEditor
return false;
}
private onClick(x: number, y: number): void
{
private onClick(x: number, y: number, render: boolean = true, force: boolean = false): void { // Updated from old code
const tile = this._tilemap[y][x];
const heightIndex = HEIGHT_SCHEME.indexOf(tile.height);
let currentHeightIndex = (tile.height === 'x' && force) ? 0 : HEIGHT_SCHEME.indexOf(tile.height);
let futureHeightIndex = 0;
switch(this._actionSettings.currentAction)
{
switch (this._actionSettings.currentAction) {
case FloorAction.DOOR:
if(tile.height !== 'x')
{
if (!force && tile.height !== 'x') {
this._doorLocation.x = x;
this._doorLocation.y = y;
this.renderTiles();
if (render) this.renderTiles();
}
return;
case FloorAction.UP:
if(tile.height === 'x') return;
futureHeightIndex = heightIndex + 1;
if (!force && tile.height === 'x') return;
futureHeightIndex = currentHeightIndex + 1;
break;
case FloorAction.DOWN:
if(tile.height === 'x' || (heightIndex <= 1)) return;
futureHeightIndex = heightIndex - 1;
if (!force && (tile.height === 'x' || (currentHeightIndex <= 1))) return;
futureHeightIndex = currentHeightIndex - 1;
break;
case FloorAction.SET:
futureHeightIndex = HEIGHT_SCHEME.indexOf(this._actionSettings.currentHeight);
@ -153,223 +154,289 @@ export class FloorplanEditor
futureHeightIndex = 0;
break;
}
if(futureHeightIndex === -1) return;
if(heightIndex === futureHeightIndex) return;
if(futureHeightIndex > 0)
{
if((x + 1) > this._width) this._width = x + 1;
if((y + 1) > this._height) this._height = y + 1;
if (futureHeightIndex === -1) return;
if (currentHeightIndex === futureHeightIndex) return;
if (!force && futureHeightIndex > 0) {
if ((x + 1) > this._width) this._width = x + 1;
if ((y + 1) > this._height) this._height = y + 1;
}
const newHeight = HEIGHT_SCHEME[futureHeightIndex];
if (!newHeight) return;
this._tilemap[y][x].height = newHeight;
if (render) this.renderTiles();
}
public renderTiles(): void {
this.clearCanvas();
this._renderer.save();
this._renderer.scale(this._zoomLevel, this._zoomLevel);
for (let y = 0; y < this._tilemap.length; y++) {
for (let x = 0; x < this._tilemap[y].length; x++) {
const tile = this._tilemap[y][x];
let assetName = tile.height;
if (this._doorLocation.x === x && this._doorLocation.y === y)
assetName = FloorplanEditor.TILE_DOOR;
if (tile.isBlocked) assetName = FloorplanEditor.TILE_BLOCKED;
if ((tile.height === 'x' || tile.height === 'X') && tile.isBlocked) assetName = 'x';
const [positionX, positionY] = getScreenPositionForTile(x, y);
const asset = spritesheet.frames[assetName];
if (asset === undefined) {
console.warn(`Asset "${assetName}" not found in spritesheet.`);
continue;
}
this._renderer.drawImage(
this._image,
asset.frame.x,
asset.frame.y,
asset.frame.w,
asset.frame.h,
positionX,
positionY,
asset.frame.w,
asset.frame.h
);
if (this._squareSelectMode && this._isPointerDown && this._selectionStart && this._selectionEnd) {
const selMinX = Math.min(this._selectionStart.x, this._selectionEnd.x);
const selMaxX = Math.max(this._selectionStart.x, this._selectionEnd.x);
const selMinY = Math.min(this._selectionStart.y, this._selectionEnd.y);
const selMaxY = Math.max(this._selectionStart.y, this._selectionEnd.y);
if (x >= selMinX && x <= selMaxX && y >= selMinY && y <= selMaxY) {
this._renderer.fillStyle = 'rgba(0, 255, 0, 0.3)';
this._renderer.fillRect(positionX, positionY, asset.frame.w, asset.frame.h);
continue;
}
}
if (tile.selected) {
this._renderer.fillStyle = tile.isBlocked ? 'rgb(128, 0, 128)' : 'rgba(0, 0, 255, 0.3)';
this._renderer.fillRect(positionX, positionY, asset.frame.w, asset.frame.h);
}
}
}
this._renderer.restore();
}
public toggleSelectAll(): void { // Added from old code
for (let y = 0; y < this._tilemap.length; y++) {
for (let x = 0; x < this._tilemap[y].length; x++) {
this._tilemap[y][x].selected = true;
if (this._actionSettings.currentAction !== FloorAction.DOOR) {
const tile = this._tilemap[y][x];
let currentHeightIndex = tile.height === 'x' ? 0 : HEIGHT_SCHEME.indexOf(tile.height);
let futureHeightIndex = 0;
switch (this._actionSettings.currentAction) {
case FloorAction.UP:
if (tile.height === 'x') continue;
futureHeightIndex = currentHeightIndex + 1;
break;
case FloorAction.DOWN:
if (tile.height === 'x' || currentHeightIndex <= 1) continue;
futureHeightIndex = currentHeightIndex - 1;
break;
case FloorAction.SET:
futureHeightIndex = HEIGHT_SCHEME.indexOf(this._actionSettings.currentHeight);
break;
case FloorAction.UNSET:
futureHeightIndex = 0;
break;
default:
continue;
}
if (futureHeightIndex !== -1 && currentHeightIndex !== futureHeightIndex) {
const newHeight = HEIGHT_SCHEME[futureHeightIndex];
if(!newHeight) return;
if(tile.isBlocked) return;
if (newHeight) {
this._tilemap[y][x].height = newHeight;
if ((x + 1) > this._width) this._width = x + 1;
if ((y + 1) > this._height) this._height = y + 1;
}
}
}
}
}
this.recalcActiveArea();
this.renderTiles();
}
public renderTiles(): void
{
this.clearCanvas();
private finalizeSquareSelection(): void { // Updated from old code
const startX = Math.floor(this._selectionStart!.x);
const startY = Math.floor(this._selectionStart!.y);
const endX = Math.floor(this._selectionEnd!.x);
const endY = Math.floor(this._selectionEnd!.y);
const minX = Math.min(startX, endX);
const maxX = Math.max(startX, endX);
const minY = Math.min(startY, endY);
const maxY = Math.max(startY, endY);
this.selectSquareField(minX, minY, maxX, maxY);
this._selectionStart = null;
this._selectionEnd = null;
this.renderTiles();
}
for(let y = 0; y < this._tilemap.length; y++)
{
for(let x = 0; x < this.tilemap[y].length; x++)
{
const tile = this.tilemap[y][x];
let assetName = tile.height;
private selectSquareField(x1: number, y1: number, x2: number, y2: number): void { // Added from old code
for (let y = y1; y <= y2; y++) {
for (let x = x1; x <= x2; x++) {
if (this._tilemap[y] && this._tilemap[y][x]) {
this._tilemap[y][x].selected = true;
this.onClick(x, y, false, true);
}
}
}
this.recalcActiveArea();
this.renderTiles();
}
if(this._doorLocation.x === x && this._doorLocation.y === y)
assetName = FloorplanEditor.TILE_DOOR;
if(tile.isBlocked) assetName = FloorplanEditor.TILE_BLOCKED;
//if((tile.height === 'x') || tile.height === 'X') continue;
const [ positionX, positionY ] = getScreenPositionForTile(x, y);
const asset = spritesheet.frames[assetName];
this.renderer.drawImage(this._image, asset.frame.x, asset.frame.y, asset.frame.w, asset.frame.h, positionX, positionY, asset.frame.w, asset.frame.h);
private recalcActiveArea(): void { // Added from old code
this._width = 0;
this._height = 0;
for (let y = 0; y < this._tilemap.length; y++) {
for (let x = 0; x < this._tilemap[y].length; x++) {
if (this._tilemap[y][x].height !== 'x') {
if ((x + 1) > this._width) this._width = x + 1;
if ((y + 1) > this._height) this._height = y + 1;
}
}
}
}
public setTilemap(map: string, blockedTiles: boolean[][]): void
{
public setTilemap(map: string, blockedTiles: boolean[][]): void {
this._tilemap = [];
const roomMapStringSplit = map.split('\r');
let width = 0;
let height = roomMapStringSplit.length;
// find the map width, height
for(let y = 0; y < height; y++)
{
for (let y = 0; y < height; y++) {
const originalRow = roomMapStringSplit[y];
if(originalRow.length === 0)
{
if (originalRow.length === 0) {
roomMapStringSplit.splice(y, 1);
height = roomMapStringSplit.length;
y--;
continue;
}
if(originalRow.length > width)
{
if (originalRow.length > width) {
width = originalRow.length;
}
}
// fill map with room heightmap tiles
for(let y = 0; y < height; y++)
{
for (let y = 0; y < height; y++) {
this._tilemap[y] = [];
const rowString = roomMapStringSplit[y];
for(let x = 0; x < width; x++)
{
for (let x = 0; x < width; x++) {
const blocked = (blockedTiles[y] && blockedTiles[y][x]) || false;
const char = rowString[x];
if(((!(char === 'x')) && (!(char === 'X')) && char))
{
if ((!(char === 'x')) && (!(char === 'X')) && char) {
this._tilemap[y][x] = new Tile(char, blocked);
}
else
{
} else {
this._tilemap[y][x] = new Tile('x', blocked);
}
}
for(let x = width; x < MAX_NUM_TILE_PER_AXIS; x++)
{
this.tilemap[y][x] = new Tile('x', false);
for (let x = width; x < MAX_NUM_TILE_PER_AXIS; x++) {
this._tilemap[y][x] = new Tile('x', false);
}
}
// fill remaining map with empty tiles
for(let y = height; y < MAX_NUM_TILE_PER_AXIS; y++)
{
if(!this.tilemap[y]) this.tilemap[y] = [];
for(let x = 0; x < MAX_NUM_TILE_PER_AXIS; x++)
{
this.tilemap[y][x] = new Tile('x', false);
for (let y = height; y < MAX_NUM_TILE_PER_AXIS; y++) {
if (!this._tilemap[y]) this._tilemap[y] = [];
for (let x = 0; x < MAX_NUM_TILE_PER_AXIS; x++) {
this._tilemap[y][x] = new Tile('x', false);
}
}
this._width = width;
this._height = height;
}
public getCurrentTilemapString(): string
{
public getCurrentTilemapString(): string {
const highestTile = this._tilemap[this._height - 1][this._width - 1];
if(highestTile.height === 'x')
{
if (highestTile.height === 'x') {
this._width = -1;
this._height = -1;
for(let y = MAX_NUM_TILE_PER_AXIS - 1; y >= 0; y--)
{
if(!this._tilemap[y]) continue;
for(let x = MAX_NUM_TILE_PER_AXIS - 1; x >= 0; x--)
{
if(!this._tilemap[y][x]) continue;
for (let y = MAX_NUM_TILE_PER_AXIS - 1; y >= 0; y--) {
if (!this._tilemap[y]) continue;
for (let x = MAX_NUM_TILE_PER_AXIS - 1; x >= 0; x--) {
if (!this._tilemap[y][x]) continue;
const tile = this._tilemap[y][x];
if(tile.height !== 'x')
{
if((x + 1) > this._width)
if (tile.height !== 'x') {
if ((x + 1) > this._width)
this._width = x + 1;
if((y + 1) > this._height)
if ((y + 1) > this._height)
this._height = y + 1;
}
}
}
}
const rows = [];
for(let y = 0; y < this._height; y++)
{
for (let y = 0; y < this._height; y++) {
const row = [];
for(let x = 0; x < this._width; x++)
{
for (let x = 0; x < this._width; x++) {
const tile = this._tilemap[y][x];
row[x] = tile.height;
}
rows[y] = row.join('');
}
return rows.join('\r');
}
public clear(): void
{
public clear(): void {
this._tilemap = [];
this._doorLocation = { x: -1, y: -1 };
this._doorLocation = { x: -1, y: -1 }; // Updated from old code (no .set method)
this._width = 0;
this._height = 0;
this._isPointerDown = false;
this._lastUsedTile = { x: -1, y: -1 };
this._lastUsedTile = { x: -1, y: -1 }; // Updated from old code (no .set method)
this._actionSettings.clear();
this.clearCanvas();
}
public clearCanvas(): void
{
this.renderer.fillStyle = '0x000000';
this.renderer.fillRect(0, 0, this._renderer.canvas.width, this._renderer.canvas.height);
public clearCanvas(): void {
this._renderer.fillStyle = '#000000';
this._renderer.fillRect(0, 0, this._renderer.canvas.width, this._renderer.canvas.height);
}
public get renderer(): CanvasRenderingContext2D
{
public zoomIn(): void { // Added from old code
this._zoomLevel = Math.min(this._zoomLevel + 0.1, 2.0);
this.adjustCanvasSize();
this.renderTiles();
}
public zoomOut(): void { // Added from old code
this._zoomLevel = Math.max(this._zoomLevel - 0.1, 0.5);
this.adjustCanvasSize();
this.renderTiles();
}
private adjustCanvasSize(): void { // Added from old code
const baseWidth = TILE_SIZE * MAX_NUM_TILE_PER_AXIS + 20;
const baseHeight = (TILE_SIZE * MAX_NUM_TILE_PER_AXIS) / 2 + 100;
this._renderer.canvas.width = baseWidth * this._zoomLevel;
this._renderer.canvas.height = baseHeight * this._zoomLevel;
}
public get zoomLevel(): number { // Added from old code
return this._zoomLevel;
}
public get renderer(): CanvasRenderingContext2D {
return this._renderer;
}
public get tilemap(): Tile[][]
{
public get tilemap(): Tile[][] {
return this._tilemap;
}
public get doorLocation(): { x: number, y: number }
{
public get doorLocation(): { x: number, y: number } {
return this._doorLocation;
}
public set doorLocation(value: { x: number, y: number })
{
public set doorLocation(value: { x: number, y: number }) {
this._doorLocation = value;
}
public get actionSettings(): ActionSettings
{
public get actionSettings(): ActionSettings {
return this._actionSettings;
}
public static get instance(): FloorplanEditor
{
if(!FloorplanEditor._INSTANCE)
{
public static get instance(): FloorplanEditor {
if (!FloorplanEditor._INSTANCE) {
FloorplanEditor._INSTANCE = new FloorplanEditor();
}
return FloorplanEditor._INSTANCE;
}
}

View File

@ -213,15 +213,5 @@ export const spritesheet = {
spriteSourceSize: { x: 0, y: 0, w: 34, h: 17 },
sourceSize: { w: 34, h: 17 },
},
},
meta: {
app: 'https://www.codeandweb.com/texturepacker',
version: '1.0',
image: 'tiles.png',
format: 'RGBA8888',
size: { w: 108, h: 190 },
scale: '1',
smartupdate:
'$TexturePacker:SmartUpdate:6d0f8373580629749f786a0b0f6c6bb9:96dff9df69bdc6938cf02f254bbe028b:accbe1e7e294ded8391337fc1c446319$',
},
}
};

View File

@ -1,8 +1,8 @@
import { GetOccupiedTilesMessageComposer, GetRoomEntryTileMessageComposer, RoomEntryTileMessageEvent, RoomOccupiedTilesMessageEvent } from '@nitrots/nitro-renderer';
import { FC, useEffect, useRef, useState } from 'react';
import { FaArrowDown, FaArrowLeft, FaArrowRight, FaArrowUp } from 'react-icons/fa';
import { FaArrowDown, FaArrowLeft, FaArrowRight, FaArrowUp, FaDotCircle, FaSearchPlus, FaSearchMinus, FaUndo } from 'react-icons/fa';
import { SendMessageComposer } from '../../../api';
import { Button, Column, ColumnProps, Grid } from '../../../common';
import { Base, Button, Column, ColumnProps, Flex, Grid } from '../../../common';
import { useMessageEvent } from '../../../hooks';
import { useFloorplanEditorContext } from '../FloorplanEditorContext';
import { FloorplanEditor } from '../common/FloorplanEditor';
@ -10,7 +10,7 @@ import { FloorplanEditor } from '../common/FloorplanEditor';
export const FloorplanCanvasView: FC<ColumnProps> = props =>
{
const { gap = 1, children = null, ...rest } = props;
const [ occupiedTilesReceived, setOccupiedTilesReceived ] = useState(false);
const [ occupiedTilesReceived , setOccupiedTilesReceived ] = useState(false);
const [ entryTileReceived, setEntryTileReceived ] = useState(false);
const { originalFloorplanSettings = null, setOriginalFloorplanSettings = null, setVisualizationSettings = null } = useFloorplanEditorContext();
const elementRef = useRef<HTMLDivElement>(null);
@ -58,7 +58,7 @@ export const FloorplanCanvasView: FC<ColumnProps> = props =>
return newValue;
});
FloorplanEditor.instance.doorLocation = { x: parser.x, y: parser.y };
FloorplanEditor.instance.doorLocation = ( parser.x, parser.y );
setEntryTileReceived(true);
});
@ -84,7 +84,7 @@ export const FloorplanCanvasView: FC<ColumnProps> = props =>
element.scrollBy({ left: 10 });
break;
}
};
}
const onPointerEvent = (event: PointerEvent) =>
{
@ -103,6 +103,20 @@ export const FloorplanCanvasView: FC<ColumnProps> = props =>
FloorplanEditor.instance.onPointerMove(event);
break;
}
}
const handleZoomIn = () => {
FloorplanEditor.instance.zoomIn();
};
const handleZoomOut = () => {
FloorplanEditor.instance.zoomOut();
};
const handleResetZoom = () => {
FloorplanEditor.instance._zoomLevel = 1.0; // Reset to default zoom
FloorplanEditor.instance.adjustCanvasSize();
FloorplanEditor.instance.renderTiles();
};
useEffect(() =>
@ -118,9 +132,9 @@ export const FloorplanCanvasView: FC<ColumnProps> = props =>
thicknessWall: originalFloorplanSettings.thicknessWall,
thicknessFloor: originalFloorplanSettings.thicknessFloor,
entryPointDir: prevValue.entryPointDir
};
}
});
};
}
}, [ originalFloorplanSettings.thicknessFloor, originalFloorplanSettings.thicknessWall, originalFloorplanSettings.wallHeight, setVisualizationSettings ]);
useEffect(() =>
@ -161,39 +175,30 @@ export const FloorplanCanvasView: FC<ColumnProps> = props =>
currentElement.removeEventListener('pointermove', onPointerEvent);
}
};
}
}, []);
const isSmallScreen = () => window.innerWidth < 768;
return (
<Column gap={ gap } { ...rest }>
<Grid gap={ 1 } overflow="hidden">
<Column center className="hidden" size={ 1 }>
<Button className="hidden" onClick={ event => onClickArrowButton('left') }>
<FaArrowLeft className="fa-icon" />
<Grid overflow="hidden" gap={ 1 }>
<Column overflow="hidden" size={ isSmallScreen() ? 10 : 12 } gap={ 1 }>
<Flex justifyContent="left" gap={ 1 }>
<Button shrink onClick={ handleZoomIn }>
<FaSearchPlus className="fa-icon" />
</Button>
</Column>
<Column gap={ 1 } overflow="hidden" size={ isSmallScreen() ? 10 : 12 }>
<div className="flex hidden justify-content-enter" >
<Button shrink onClick={ event => onClickArrowButton('up') }>
<FaArrowUp className="fa-icon" />
<Button shrink onClick={ handleResetZoom }>
<FaDotCircle className="fa-icon" />
</Button>
</div>
<div ref={ elementRef } className="overflow-auto" />
<div className="flex hidden justify-center">
<Button shrink onClick={ event => onClickArrowButton('down') }>
<FaArrowDown className="fa-icon" />
</Button>
</div>
</Column>
<Column center className="hidden" size={ 1 }>
<Button className="hidden" onClick={ event => onClickArrowButton('right') }>
<FaArrowRight className="fa-icon" />
<Button shrink onClick={ handleZoomOut }>
<FaSearchMinus className="fa-icon" />
</Button>
</Flex>
<Base overflow="auto" innerRef={ elementRef } />
</Column>
</Grid>
{ children }
</Column>
);
};
}

View File

@ -13,173 +13,168 @@ const MAX_WALL_HEIGHT: number = 16;
const MIN_FLOOR_HEIGHT: number = 0;
const MAX_FLOOR_HEIGHT: number = 26;
export const FloorplanOptionsView: FC<{}> = props =>
{
export const FloorplanOptionsView: FC<{}> = props => {
const { visualizationSettings = null, setVisualizationSettings = null } = useFloorplanEditorContext();
const [ floorAction, setFloorAction ] = useState(FloorAction.SET);
const [ floorHeight, setFloorHeight ] = useState(0);
const [floorAction, setFloorAction] = useState(FloorAction.SET);
const [floorHeight, setFloorHeight] = useState(0);
const [isSquareSelectMode, setIsSquareSelectMode] = useState(false);
const selectAction = (action: number) =>
{
const selectAction = (action: number) => {
setFloorAction(action);
FloorplanEditor.instance.actionSettings.currentAction = action;
};
const changeDoorDirection = () =>
{
setVisualizationSettings(prevValue =>
{
const newValue = { ...prevValue };
if(newValue.entryPointDir < 7)
{
++newValue.entryPointDir;
}
else
{
newValue.entryPointDir = 0;
}
const toggleSquareSelectMode = () => {
setIsSquareSelectMode(prev => {
const newValue = !prev;
FloorplanEditor.instance.setSquareSelectMode(newValue);
return newValue;
});
};
const onFloorHeightChange = (value: number) =>
{
if(isNaN(value) || (value <= 0)) value = 0;
if(value > 26) value = 26;
const changeDoorDirection = () => {
setVisualizationSettings(prevValue => {
const newValue = { ...prevValue };
newValue.entryPointDir = newValue.entryPointDir < 7 ? newValue.entryPointDir + 1 : 0;
return newValue;
});
};
const onFloorHeightChange = (value: number) => {
if (isNaN(value) || value <= 0) value = 0;
if (value > MAX_FLOOR_HEIGHT) value = MAX_FLOOR_HEIGHT;
setFloorHeight(value);
FloorplanEditor.instance.actionSettings.currentHeight = value.toString(36);
};
const onFloorThicknessChange = (value: number) =>
{
setVisualizationSettings(prevValue =>
{
const newValue = { ...prevValue };
newValue.thicknessFloor = value;
return newValue;
});
const onFloorThicknessChange = (value: number) => {
setVisualizationSettings(prevValue => ({
...prevValue,
thicknessFloor: value,
}));
};
const onWallThicknessChange = (value: number) =>
{
setVisualizationSettings(prevValue =>
{
const newValue = { ...prevValue };
newValue.thicknessWall = value;
return newValue;
});
const onWallThicknessChange = (value: number) => {
setVisualizationSettings(prevValue => ({
...prevValue,
thicknessWall: value,
}));
};
const onWallHeightChange = (value: number) =>
{
if(isNaN(value) || (value <= 0)) value = MIN_WALL_HEIGHT;
if(value > MAX_WALL_HEIGHT) value = MAX_WALL_HEIGHT;
setVisualizationSettings(prevValue =>
{
const newValue = { ...prevValue };
newValue.wallHeight = value;
return newValue;
});
const onWallHeightChange = (value: number) => {
if (isNaN(value) || value <= 0) value = MIN_WALL_HEIGHT;
if (value > MAX_WALL_HEIGHT) value = MAX_WALL_HEIGHT;
setVisualizationSettings(prevValue => ({
...prevValue,
wallHeight: value,
}));
};
const increaseWallHeight = () =>
{
let height = (visualizationSettings.wallHeight + 1);
if(height > MAX_WALL_HEIGHT) height = MAX_WALL_HEIGHT;
onWallHeightChange(height);
const increaseWallHeight = () => {
onWallHeightChange(Math.min(visualizationSettings.wallHeight + 1, MAX_WALL_HEIGHT));
};
const decreaseWallHeight = () =>
{
let height = (visualizationSettings.wallHeight - 1);
if(height <= 0) height = MIN_WALL_HEIGHT;
onWallHeightChange(height);
const decreaseWallHeight = () => {
onWallHeightChange(Math.max(visualizationSettings.wallHeight - 1, MIN_WALL_HEIGHT));
};
return (
<div className="flex flex-col">
<Grid>
<Column gap={ 1 } size={ 5 }>
<Text bold>{ LocalizeText('floor.plan.editor.draw.mode') }</Text>
<Flex gap={ 3 }>
<Column gap={1} size={5}>
<Text bold>{LocalizeText('floor.plan.editor.draw.mode')}</Text>
<Flex gap={3}>
<div className="flex gap-1">
<LayoutGridItem itemActive={ (floorAction === FloorAction.SET) } onClick={ event => selectAction(FloorAction.SET) }>
<LayoutGridItem itemActive={floorAction === FloorAction.SET} onClick={() => selectAction(FloorAction.SET)}>
<i className="nitro-icon icon-set-tile" />
</LayoutGridItem>
<LayoutGridItem itemActive={ (floorAction === FloorAction.UNSET) } onClick={ event => selectAction(FloorAction.UNSET) }>
<LayoutGridItem itemActive={floorAction === FloorAction.UNSET} onClick={() => selectAction(FloorAction.UNSET)}>
<i className="nitro-icon icon-unset-tile" />
</LayoutGridItem>
</div>
<div className="flex gap-1">
<LayoutGridItem itemActive={ (floorAction === FloorAction.UP) } onClick={ event => selectAction(FloorAction.UP) }>
<LayoutGridItem itemActive={floorAction === FloorAction.UP} onClick={() => selectAction(FloorAction.UP)}>
<i className="nitro-icon icon-increase-height" />
</LayoutGridItem>
<LayoutGridItem itemActive={ (floorAction === FloorAction.DOWN) } onClick={ event => selectAction(FloorAction.DOWN) }>
<LayoutGridItem itemActive={floorAction === FloorAction.DOWN} onClick={() => selectAction(FloorAction.DOWN)}>
<i className="nitro-icon icon-decrease-height" />
</LayoutGridItem>
</div>
<LayoutGridItem itemActive={ (floorAction === FloorAction.DOOR) } onClick={ event => selectAction(FloorAction.DOOR) }>
<LayoutGridItem itemActive={floorAction === FloorAction.DOOR} onClick={() => selectAction(FloorAction.DOOR)}>
<i className="nitro-icon icon-set-door" />
</LayoutGridItem>
<LayoutGridItem onClick={() => FloorplanEditor.instance.toggleSelectAll()}>
<i className={`nitro-icon ${floorAction === FloorAction.UNSET ? 'icon-set-deselect' : 'icon-set-select'}`} />
</LayoutGridItem>
<LayoutGridItem itemActive={isSquareSelectMode} onClick={toggleSquareSelectMode}>
<i className={`nitro-icon ${isSquareSelectMode ? 'icon-set-active-squaresselect' : 'icon-set-squaresselect'}`} />
</LayoutGridItem>
</div>
</Flex>
</Column>
<Column alignItems="center" size={ 4 }>
<Text bold>{ LocalizeText('floor.plan.editor.enter.direction') }</Text>
<i className={ `nitro-icon icon-door-direction-${ visualizationSettings.entryPointDir } cursor-pointer` } onClick={ changeDoorDirection } />
<Column alignItems="center" size={4}>
<Text bold>{LocalizeText('floor.plan.editor.enter.direction')}</Text>
<i
className={`nitro-icon icon-door-direction-${visualizationSettings.entryPointDir} cursor-pointer`}
onClick={changeDoorDirection}
/>
</Column>
<Column size={ 3 }>
<Text bold>{ LocalizeText('floor.editor.wall.height') }</Text>
<Column size={3}>
<Text bold>{LocalizeText('floor.editor.wall.height')}</Text>
<div className="flex items-center gap-1">
<FaCaretLeft className="cursor-pointer fa-icon" onClick={ decreaseWallHeight } />
<input className="min-h-[calc(1.5em+ .5rem+2px)] px-[.5rem] py-[.25rem] rounded-[.2rem] form-control-sm quantity-input" type="number" value={ visualizationSettings.wallHeight } onChange={ event => onWallHeightChange(event.target.valueAsNumber) } />
<FaCaretRight className="cursor-pointer fa-icon" onClick={ increaseWallHeight } />
<FaCaretLeft className="cursor-pointer fa-icon" onClick={decreaseWallHeight} />
<input
className="min-h-[calc(1.5em+.5rem+2px)] px-[.5rem] py-[.25rem] rounded-[.2rem] form-control-sm quantity-input"
type="number"
value={visualizationSettings.wallHeight}
onChange={event => onWallHeightChange(event.target.valueAsNumber)}
/>
<FaCaretRight className="cursor-pointer fa-icon" onClick={increaseWallHeight} />
</div>
</Column>
</Grid>
<Grid>
<Column size={ 6 }>
<Text bold>{ LocalizeText('floor.plan.editor.tile.height') }: { floorHeight }</Text>
<Column size={6}>
<Text bold>{LocalizeText('floor.plan.editor.tile.height')}: {floorHeight}</Text>
<ReactSlider
className="nitro-slider"
max={ MAX_FLOOR_HEIGHT }
min={ MIN_FLOOR_HEIGHT }
renderThumb={ ({ style, ...rest }, state) => <div style={ { backgroundColor: `#${ COLORMAP[state.valueNow.toString(33)] }`, ...style } } { ...rest }>{ state.valueNow }</div> }
step={ 1 }
value={ floorHeight }
onChange={ event => onFloorHeightChange(event) } />
max={MAX_FLOOR_HEIGHT}
min={MIN_FLOOR_HEIGHT}
renderThumb={({ key, style, ...rest }, state) => (
<div
key={key} // Explicitly pass key directly
style={{ backgroundColor: `#${COLORMAP[state.valueNow.toString(33)]}`, ...style }}
{...rest}
>
{state.valueNow}
</div>
)}
step={1}
value={floorHeight}
onChange={value => onFloorHeightChange(value)}
/>
</Column>
<Column size={ 6 }>
<Text bold>{ LocalizeText('floor.plan.editor.room.options') }</Text>
<Column size={6}>
<Text bold>{LocalizeText('floor.plan.editor.room.options')}</Text>
<Flex className="items-center">
<select className="min-h-[calc(1.5em+ .5rem+2px)] px-[.5rem] py-[.25rem] rounded-[.2rem] form-control-sm" value={ visualizationSettings.thicknessWall } onChange={ event => onWallThicknessChange(parseInt(event.target.value)) }>
<option value={ 0 }>{ LocalizeText('navigator.roomsettings.wall_thickness.thinnest') }</option>
<option value={ 1 }>{ LocalizeText('navigator.roomsettings.wall_thickness.thin') }</option>
<option value={ 2 }>{ LocalizeText('navigator.roomsettings.wall_thickness.normal') }</option>
<option value={ 3 }>{ LocalizeText('navigator.roomsettings.wall_thickness.thick') }</option>
<select
className="min-h-[calc(1.5em+.5rem+2px)] px-[.5rem] py-[.25rem] rounded-[.2rem] form-control-sm"
value={visualizationSettings.thicknessWall}
onChange={event => onWallThicknessChange(parseInt(event.target.value))}
>
<option value={0}>{LocalizeText('navigator.roomsettings.wall_thickness.thinnest')}</option>
<option value={1}>{LocalizeText('navigator.roomsettings.wall_thickness.thin')}</option>
<option value={2}>{LocalizeText('navigator.roomsettings.wall_thickness.normal')}</option>
<option value={3}>{LocalizeText('navigator.roomsettings.wall_thickness.thick')}</option>
</select>
<select className="min-h-[calc(1.5em+ .5rem+2px)] px-[.5rem] py-[.25rem] rounded-[.2rem] form-control-sm" value={ visualizationSettings.thicknessFloor } onChange={ event => onFloorThicknessChange(parseInt(event.target.value)) }>
<option value={ 0 }>{ LocalizeText('navigator.roomsettings.floor_thickness.thinnest') }</option>
<option value={ 1 }>{ LocalizeText('navigator.roomsettings.floor_thickness.thin') }</option>
<option value={ 2 }>{ LocalizeText('navigator.roomsettings.floor_thickness.normal') }</option>
<option value={ 3 }>{ LocalizeText('navigator.roomsettings.floor_thickness.thick') }</option>
<select
className="min-h-[calc(1.5em+.5rem+2px)] px-[.5rem] py-[.25rem] rounded-[.2rem] form-control-sm"
value={visualizationSettings.thicknessFloor}
onChange={event => onFloorThicknessChange(parseInt(event.target.value))}
>
<option value={0}>{LocalizeText('navigator.roomsettings.floor_thickness.thinnest')}</option>
<option value={1}>{LocalizeText('navigator.roomsettings.floor_thickness.thin')}</option>
<option value={2}>{LocalizeText('navigator.roomsettings.floor_thickness.normal')}</option>
<option value={3}>{LocalizeText('navigator.roomsettings.floor_thickness.thick')}</option>
</select>
</Flex>
</Column>

View File

@ -0,0 +1,9 @@
.nitro-floorplan-editor {
width: 760px;
height: 500px;
}
.floorplan-import-export {
width: 630px;
height: 475px;
}

659
src/css/icons/icons.css Normal file
View File

@ -0,0 +1,659 @@
.nitro-icon {
display: inline-block;
background: transparent;
background-position: center;
background-repeat: no-repeat;
outline: 0;
}
.nitro-icon:hover {
transform: translate(-1px, -1px);
filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.5));
}
.nitro-icon:active {
transform: none;
filter: none;
}
.nitro-icon.icon-nitro-light {
background-image: url("@/assets/images/nitro/nitro-n-light.svg");
}
.nitro-icon.icon-nitro-dark {
background-image: url("@/assets/images/nitro/nitro-n-dark.svg");
}
.nitro-icon.icon-nitro-light,
.nitro-icon.icon-nitro-dark {
width: 100%;
height: 40px;
}
.nitro-icon.icon-catalog {
background-image: url("@/assets/images/toolbar/icons/catalog.png");
width: 37px;
height: 36px;
}
.nitro-icon.icon-game {
background-image: url("@/assets/images/toolbar/icons/game.png");
width: 44px;
height: 25px;
}
.nitro-icon.icon-rooms {
background-image: url("@/assets/images/toolbar/icons/rooms.png");
width: 44px;
height: 30px;
}
.nitro-icon.icon-house {
background-image: url("@/assets/images/toolbar/icons/house.png");
width: 32px;
height: 30px;
}
.nitro-icon.gray {
opacity: 0.5;
}
.nitro-icon.icon-inventory {
background-image: url("@/assets/images/toolbar/icons/inventory.png");
width: 44px;
height: 41px;
}
.nitro-icon.icon-modtools {
background-image: url("@/assets/images/toolbar/icons/modtools.png");
width: 29px;
height: 34px;
}
.nitro-icon.icon-friendall {
background-image: url("@/assets/images/toolbar/icons/friend_all.png");
width: 32px;
height: 33px;
}
.nitro-icon.icon-friendsearch {
background-image: url("@/assets/images/toolbar/icons/friend_search.png");
width: 29px;
height: 33px;
}
.nitro-icon.icon-sendmessage {
background-image: url("@/assets/images/toolbar/icons/sendmessage.png");
width: 20px;
height: 21px;
}
.nitro-icon.icon-me-talents {
background-image: url("@/assets/images/toolbar/icons/me-menu/talents.png");
width: 32px;
height: 30px;
}
.nitro-icon.icon-me-helper-tool {
background-image: url("@/assets/images/toolbar/icons/me-menu/helper-tool.png");
width: 32px;
height: 30px;
}
.nitro-icon.icon-me-profile {
background-image: url("@/assets/images/toolbar/icons/me-menu/profile.png");
width: 32px;
height: 30px;
}
.nitro-icon.icon-me-forums {
background-image: url("@/assets/images/toolbar/icons/me-menu/forums.png");
width: 32px;
height: 30px;
}
.nitro-icon.icon-me-rooms {
background-image: url("@/assets/images/toolbar/icons/me-menu/my-rooms.png");
width: 30px;
height: 30px;
}
.nitro-icon.icon-me-achievements {
background-image: url("@/assets/images/toolbar/icons/me-menu/achievements.png");
width: 31px;
height: 30px;
}
.nitro-icon.icon-me-clothing {
background-image: url("@/assets/images/toolbar/icons/me-menu/clothing.png");
width: 27px;
height: 30px;
}
.nitro-icon.icon-me-settings {
background-image: url("@/assets/images/toolbar/icons/me-menu/cog.png");
width: 28px;
height: 34px;
}
.nitro-icon.icon-cog {
background: url("@/assets/images/icons/icon_cog.png");
width: 14px;
height: 15px;
}
.nitro-icon.icon-help {
background: url("@/assets/images/icons/help.png");
width: 13px;
height: 23px;
}
.nitro-icon.icon-joinroom {
background-image: url("@/assets/images/toolbar/icons/joinroom.png");
width: 21px;
height: 21px;
}
.nitro-icon.icon-habbo {
background-image: url("@/assets/images/toolbar/icons/habbo.png");
width: 28px;
height: 28px;
}
.nitro-icon.icon-camera {
background-image: url("@/assets/images/toolbar/icons/camera.png");
width: 38px;
height: 45px;
}
.nitro-icon.icon-message {
background-image: url("@/assets/images/toolbar/icons/message.png");
width: 36px;
height: 32px;
}
.nitro-icon.icon-message.is-unseen {
background-image: url("@/assets/images/toolbar/icons/message_unsee.gif");
}
.nitro-icon.icon-wired-trigger {
background-image: url("@/assets/images/wired/icon_trigger.png");
width: 13px;
height: 14px;
}
.nitro-icon.icon-wired-condition {
background-image: url("@/assets/images/wired/icon_condition.png");
width: 13px;
height: 14px;
}
.nitro-icon.icon-wired-action {
background-image: url("@/assets/images/wired/icon_action.png");
width: 13px;
height: 14px;
}
.nitro-icon.chatstyles-icon {
background-image: url("@/assets/images/chat/styles-icon.png");
width: 17px;
height: 19px;
filter: grayscale(100%);
}
.nitro-icon.chatstyles-icon:hover {
filter: grayscale(0%);
}
.nitro-icon.pencil-icon {
background-image: url("@/assets/images/infostand/pencil-icon.png");
width: 17px;
height: 18px;
}
.nitro-icon.disk-icon {
background-image: url("@/assets/images/infostand/disk-icon.png");
width: 14px;
height: 14px;
}
.nitro-icon.disk-creator {
background-image: url("@/assets/images/infostand/disk-creator.png");
width: 14px;
height: 14px;
}
.nitro-icon.trade-locked-icon {
background-image: url("@/assets/images/inventory/trading/locked-icon.png");
width: 29px;
height: 43px;
}
.nitro-icon.trade-unlocked-icon {
background-image: url("@/assets/images/inventory/trading/unlocked-icon.png");
width: 29px;
height: 43px;
}
.nitro-icon.modtool-room-icon {
background-image: url("@/assets/images/modtool/room.png");
width: 20px;
height: 15px;
}
.nitro-icon.modtool-chatlog-icon {
background-image: url("@/assets/images/modtool/chatlog.gif");
width: 20px;
height: 15px;
}
.nitro-icon.modtool-user-icon {
background-image: url("@/assets/images/modtool/user.gif");
width: 20px;
height: 15px;
}
.nitro-icon.modtool-reports-icon {
background-image: url("@/assets/images/modtool/reports.png");
width: 20px;
height: 15px;
}
.nitro-icon.modtool-wrench-icon {
background-image: url("@/assets/images/modtool/wrench.gif");
width: 20px;
height: 15px;
}
.nitro-icon.modtool-key-icon {
background-image: url("@/assets/images/modtool/key.gif");
width: 20px;
height: 15px;
}
.nitro-icon.icon-catalogue-hc_small {
background-image: url("@/assets/images/catalog/hc_small.png");
width: 31px;
height: 17px;
}
.nitro-icon.icon-catalogue-hc_big {
background: url("@/assets/images/catalog/hc_big.png");
width: 68px;
height: 40px;
}
.nitro-icon.icon-sign-exclamation {
background: url("@/assets/images/icons/sign-exclamation.png");
width: 7px;
height: 17px;
}
.nitro-icon.icon-sign-heart {
background: url("@/assets/images/icons/sign-heart.png");
width: 15px;
height: 13px;
}
.nitro-icon.icon-sign-red {
background: url("@/assets/images/icons/sign-red.png");
width: 11px;
height: 19px;
}
.nitro-icon.icon-sign-yellow {
background: url("@/assets/images/icons/sign-yellow.png");
width: 11px;
height: 19px;
}
.nitro-icon.icon-sign-skull {
background: url("@/assets/images/icons/sign-skull.png");
width: 12px;
height: 12px;
}
.nitro-icon.icon-sign-smile {
background: url("@/assets/images/icons/sign-smile.png");
width: 7px;
height: 14px;
}
.nitro-icon.icon-sign-soccer {
background: url("@/assets/images/icons/sign-soccer.png");
width: 20px;
height: 20px;
}
.nitro-icon.icon-house-small {
background: url("@/assets/images/icons/house-small.png");
width: 19px;
height: 14px;
}
.nitro-icon.icon-camera-small {
background: url("@/assets/images/icons/camera-small.png");
width: 17px;
height: 15px;
}
.nitro-icon.icon-small-room {
background: url("@/assets/images/icons/small-room.png");
width: 17px;
height: 16px;
}
.nitro-icon.icon-cog {
background: url("@/assets/images/icons/cog.png");
width: 21px;
height: 21px;
}
.nitro-icon.icon-chat-history {
background: url("@/assets/images/icons/chat-history.png");
width: 17px;
height: 21px;
}
.nitro-icon.icon-room-link {
background: url("@/assets/images/icons/room-link.png");
width: 17px;
height: 15px;
}
.nitro-icon.icon-zoom-more {
background: url("@/assets/images/icons/zoom-more.png");
width: 12px;
height: 22px;
}
.nitro-icon.icon-zoom-less {
background: url("@/assets/images/icons/zoom-less.png");
width: 12px;
height: 22px;
}
.nitro-icon.icon-like-room {
background: url("@/assets/images/icons/like-room.png");
width: 20px;
height: 22px;
}
.nitro-icon.icon-arrows {
background: url("@/assets/images/icons/arrows.png");
width: 17px;
height: 15px;
}
.nitro-icon.icon-camera-colormatrix {
background: url("@/assets/images/icons/camera-colormatrix.png");
width: 32px;
height: 21px;
}
.nitro-icon.icon-camera-composite {
background: url("@/assets/images/icons/camera-composite.png");
width: 32px;
height: 21px;
}
.nitro-icon.icon-pf-online {
background: url("@/assets/images/profile/icons/online.gif");
width: 40px;
height: 16px;
}
.nitro-icon.icon-pf-offline {
background: url("@/assets/images/profile/icons/offline.png");
width: 39px;
height: 16px;
}
.nitro-icon.icon-pf-tick {
background: url("@/assets/images/profile/icons/tick.png");
width: 11px;
height: 10px;
}
.nitro-icon.icon-group-type-0 {
background: url("@/assets/images/groups/icons/grouptype_icon_0.png");
width: 16px;
height: 16px;
}
.nitro-icon.icon-group-type-1 {
background: url("@/assets/images/groups/icons/grouptype_icon_1.png");
width: 16px;
height: 16px;
}
.nitro-icon.icon-group-type-2 {
background: url("@/assets/images/groups/icons/grouptype_icon_2.png");
width: 16px;
height: 16px;
}
.nitro-icon.icon-group-decorate {
background: url("@/assets/images/groups/icons/group_decorate_icon.png");
width: 15px;
height: 15px;
}
.nitro-icon.icon-group-member {
background: url("@/assets/images/groups/icons/group_icon_big_member.png");
width: 20px;
height: 20px;
}
.nitro-icon.icon-group-admin {
background: url("@/assets/images/groups/icons/group_icon_big_admin.png");
width: 20px;
height: 20px;
}
.nitro-icon.icon-group-owner {
background: url("@/assets/images/groups/icons/group_icon_big_owner.png");
width: 20px;
height: 20px;
}
.nitro-icon.icon-group-favorite {
background: url("@/assets/images/groups/icons/group_favorite.png");
width: 14px;
height: 14px;
}
.nitro-icon.icon-group-not-favorite {
background: url("@/assets/images/groups/icons/group_notfavorite.png");
width: 14px;
height: 14px;
}
.nitro-icon.icon-group-small-admin {
background: url("@/assets/images/groups/icons/group_icon_admin.png");
width: 11px;
height: 13px;
}
.nitro-icon.icon-group-small-not-admin {
background: url("@/assets/images/groups/icons/group_icon_not_admin.png");
width: 11px;
height: 13px;
}
.nitro-icon.icon-group-small-owner {
background: url("@/assets/images/groups/icons/group_icon_small_owner.png");
width: 13px;
height: 13px;
}
.nitro-icon.icon-navigator-info {
background: url("@/assets/images/navigator/icons/info.png");
width: 18px;
height: 18px;
}
.nitro-icon.icon-navigator-room-locked {
background: url("@/assets/images/navigator/icons/room_locked.png");
width: 13px;
height: 16px;
}
.nitro-icon.icon-navigator-room-password {
background: url("@/assets/images/navigator/icons/room_password.png");
width: 13px;
height: 16px;
}
.nitro-icon.icon-navigator-room-invisible {
background: url("@/assets/images/navigator/icons/room_invisible.png");
width: 13px;
height: 16px;
}
.nitro-icon.icon-navigator-room-group {
background: url("@/assets/images/navigator/icons/room_group.png");
width: 13px;
height: 11px;
}
.nitro-icon.icon-youtube-next {
background: url("@/assets/images/room-widgets/youtube-widget/next.png");
width: 21px;
height: 16px;
}
.nitro-icon.icon-youtube-prev {
background: url("@/assets/images/room-widgets/youtube-widget/prev.png");
width: 21px;
height: 16px;
}
.nitro-icon.icon-hc-banner {
background: url("@/assets/images/catalog/hc_big.png");
width: 68px;
height: 40px;
}
.nitro-icon.icon-set-tile {
background-image: url("@/assets/images/floorplaneditor/icon-tile-set.png");
width: 40px;
height: 40px;
}
.nitro-icon.icon-unset-tile {
background-image: url("@/assets/images/floorplaneditor/icon-tile-unset.png");
width: 40px;
height: 40px;
}
.nitro-icon.icon-increase-height {
background-image: url("@/assets/images/floorplaneditor/icon-tile-up.png");
width: 40px;
height: 40px;
}
.nitro-icon.icon-decrease-height {
background-image: url("@/assets/images/floorplaneditor/icon-tile-down.png");
width: 40px;
height: 40px;
}
.nitro-icon.icon-set-door {
background-image: url("@/assets/images/floorplaneditor/icon-door.png");
width: 40px;
height: 40px;
}
.nitro-icon.icon-door-direction-0 {
background-image: url("@/assets/images/floorplaneditor/door-direction-0.png");
width: 80px;
height: 45px;
}
.nitro-icon.icon-door-direction-1 {
background-image: url("@/assets/images/floorplaneditor/door-direction-1.png");
width: 80px;
height: 45px;
}
.nitro-icon.icon-door-direction-2 {
background-image: url("@/assets/images/floorplaneditor/door-direction-2.png");
width: 80px;
height: 45px;
}
.nitro-icon.icon-door-direction-3 {
background-image: url("@/assets/images/floorplaneditor/door-direction-3.png");
width: 80px;
height: 45px;
}
.nitro-icon.icon-door-direction-4 {
background-image: url("@/assets/images/floorplaneditor/door-direction-4.png");
width: 80px;
height: 45px;
}
.nitro-icon.icon-door-direction-5 {
background-image: url("@/assets/images/floorplaneditor/door-direction-5.png");
width: 80px;
height: 45px;
}
.nitro-icon.icon-door-direction-6 {
background-image: url("@/assets/images/floorplaneditor/door-direction-6.png");
width: 80px;
height: 45px;
}
.nitro-icon.icon-door-direction-7 {
background-image: url("@/assets/images/floorplaneditor/door-direction-7.png");
width: 80px;
height: 45px;
}
.nitro-icon.icon-set-select {
background-image: url('@/assets/images/floorplaneditor/icon-select.png');
width: 40px;
height: 40px;
}
.nitro-icon.icon-set-deselect {
background-image: url('@/assets/images/floorplaneditor/icon-deselect.png');
width: 40px;
height: 40px;
}
.nitro-icon.icon-set-squaresselect {
background-image: url('@/assets/images/floorplaneditor/icon-squaresselect.png');
width: 40px;
height: 40px;
}
.nitro-icon.icon-set-active-squaresselect {
background-image: url('@/assets/images/floorplaneditor/icon-squaresselect.png');
width: 40px;
height: 40px;
}
.nitro-icon.icon-tickets {
background-image: url("@/assets/images/icons/tickets.png");
width: 17px;
height: 17px;
}
.nitro-icon.icon-user {
background-image: url("@/assets/images/icons/user.png");
width: 18px;
height: 19px;
}
.nitro-icon.icon-loading {
background-image: url("@/assets/images/ui/loading_icon.png");
}
.nitro-icon.icon-loading.with-size {
width: 16px;
height: 16px;
}

View File

@ -190,636 +190,6 @@ body {
@apply bg-[-19px];
}
}
.nitro-icon {
@apply inline-block bg-transparent bg-center bg-no-repeat outline-0;
&:hover {
@apply translate-x-[-1px] translate-y-[-1px] drop-shadow-hover
}
&:active {
@apply transform-none filter-none
}
&.icon-nitro-light {
background-image: url("@/assets/images/nitro/nitro-n-light.svg");
}
&.icon-nitro-dark {
background-image: url("@/assets/images/nitro/nitro-n-dark.svg");
}
&.icon-nitro-light,
&.icon-nitro-dark {
width: 100%;
height: 40px;
}
&.icon-catalog {
background-image: url("@/assets/images/toolbar/icons/catalog.png");
width: 37px;
height: 36px;
}
&.icon-game {
background-image: url("@/assets/images/toolbar/icons/game.png");
width: 44px;
height: 25px;
}
&.icon-rooms {
background-image: url("@/assets/images/toolbar/icons/rooms.png");
width: 44px;
height: 30px;
}
&.icon-house {
background-image: url("@/assets/images/toolbar/icons/house.png");
height: 30px;
width: 32px;
}
&.gray {
opacity: 0.5;
}
&.icon-inventory {
background-image: url("@/assets/images/toolbar/icons/inventory.png");
height: 41px;
width: 44px;
}
&.icon-modtools {
background-image: url("@/assets/images/toolbar/icons/modtools.png");
height: 34px;
width: 29px;
}
&.icon-friendall {
background-image: url("@/assets/images/toolbar/icons/friend_all.png");
height: 33px;
width: 32px;
}
&.icon-friendsearch {
background-image: url("@/assets/images/toolbar/icons/friend_search.png");
height: 33px;
width: 29px;
}
&.icon-sendmessage {
background-image: url("@/assets/images/toolbar/icons/sendmessage.png");
width: 20px;
height: 21px;
}
&.icon-me-talents {
background-image: url("@/assets/images/toolbar/icons/me-menu/talents.png");
width: 32px;
height: 30px;
}
&.icon-me-helper-tool {
background-image: url("@/assets/images/toolbar/icons/me-menu/helper-tool.png");
width: 32px;
height: 30px;
}
&.icon-me-profile {
background-image: url("@/assets/images/toolbar/icons/me-menu/profile.png");
width: 32px;
height: 30px;
}
&.icon-me-forums {
background-image: url("@/assets/images/toolbar/icons/me-menu/forums.png");
width: 32px;
height: 30px;
}
&.icon-me-rooms {
background-image: url("@/assets/images/toolbar/icons/me-menu/my-rooms.png");
width: 30px;
height: 30px;
}
&.icon-me-achievements {
background-image: url("@/assets/images/toolbar/icons/me-menu/achievements.png");
width: 31px;
height: 30px;
}
&.icon-me-clothing {
background-image: url("@/assets/images/toolbar/icons/me-menu/clothing.png");
width: 27px;
height: 30px;
}
&.icon-me-settings {
background-image: url("@/assets/images/toolbar/icons/me-menu/cog.png");
width: 28px;
height: 34px;
}
&.icon-cog {
background: url("@/assets/images/icons/icon_cog.png");
width: 14px;
height: 15px;
}
&.icon-help {
background: url("@/assets/images/icons/help.png");
width: 13px;
height: 23px;
}
&.icon-joinroom {
background-image: url("@/assets/images/toolbar/icons/joinroom.png");
width: 21px;
height: 21px;
}
&.icon-habbo {
background-image: url("@/assets/images/toolbar/icons/habbo.png");
width: 28px;
height: 28px;
}
&.icon-camera {
background-image: url("@/assets/images/toolbar/icons/camera.png");
width: 38px;
height: 45px;
}
&.icon-message {
background-image: url("@/assets/images/toolbar/icons/message.png");
width: 36px;
height: 32px;
&.is-unseen {
background-image: url("@/assets/images/toolbar/icons/message_unsee.gif");
}
}
&.icon-wired-trigger {
background-image: url("@/assets/images/wired/icon_trigger.png");
width: 13px;
height: 14px;
}
&.icon-wired-condition {
background-image: url("@/assets/images/wired/icon_condition.png");
width: 13px;
height: 14px;
}
&.icon-wired-action {
background-image: url("@/assets/images/wired/icon_action.png");
width: 13px;
height: 14px;
}
&.chatstyles-icon {
background-image: url("@/assets/images/chat/styles-icon.png");
width: 17px;
height: 19px;
filter: grayscale(100%);
&:hover {
filter: grayscale(0%);
}
}
&.pencil-icon {
background-image: url("@/assets/images/infostand/pencil-icon.png");
width: 17px;
height: 18px;
}
&.disk-icon {
background-image: url("@/assets/images/infostand/disk-icon.png");
width: 14px;
height: 14px;
}
&.disk-creator {
background-image: url("@/assets/images/infostand/disk-creator.png");
width: 14px;
height: 14px;
}
&.trade-locked-icon {
background-image: url("@/assets/images/inventory/trading/locked-icon.png");
width: 29px;
height: 43px;
}
&.trade-unlocked-icon {
background-image: url("@/assets/images/inventory/trading/unlocked-icon.png");
width: 29px;
height: 43px;
}
&.modtool-room-icon {
background-image: url("@/assets/images/modtool/room.png");
width: 20px;
height: 15px;
}
&.modtool-chatlog-icon {
background-image: url("@/assets/images/modtool/chatlog.gif");
width: 20px;
height: 15px;
}
&.modtool-user-icon {
background-image: url("@/assets/images/modtool/user.gif");
width: 20px;
height: 15px;
}
&.modtool-reports-icon {
background-image: url("@/assets/images/modtool/reports.png");
width: 20px;
height: 15px;
}
&.modtool-wrench-icon {
background-image: url("@/assets/images/modtool/wrench.gif");
width: 20px;
height: 15px;
}
&.modtool-key-icon {
background-image: url("@/assets/images/modtool/key.gif");
width: 20px;
height: 15px;
}
&.icon-catalogue-hc_small {
background-image: url("@/assets/images/catalog/hc_small.png");
height: 17px;
width: 31px;
}
&.icon-catalogue-hc_big {
background: url("@/assets/images/catalog/hc_big.png");
width: 68px;
height: 40px;
}
&.icon-sign-exclamation {
background: url("@/assets/images/icons/sign-exclamation.png");
width: 7px;
height: 17px;
}
&.icon-sign-heart {
background: url("@/assets/images/icons/sign-heart.png");
width: 15px;
height: 13px;
}
&.icon-sign-red {
background: url("@/assets/images/icons/sign-red.png");
width: 11px;
height: 19px;
}
&.icon-sign-yellow {
background: url("@/assets/images/icons/sign-yellow.png");
width: 11px;
height: 19px;
}
&.icon-sign-skull {
background: url("@/assets/images/icons/sign-skull.png");
width: 12px;
height: 12px;
}
&.icon-sign-smile {
background: url("@/assets/images/icons/sign-smile.png");
width: 7px;
height: 14px;
}
&.icon-sign-soccer {
background: url("@/assets/images/icons/sign-soccer.png");
width: 20px;
height: 20px;
}
&.icon-house-small {
background: url("@/assets/images/icons/house-small.png");
width: 19px;
height: 14px;
}
&.icon-camera-small {
background: url("@/assets/images/icons/camera-small.png");
width: 17px;
height: 15px;
}
&.icon-small-room {
background: url("@/assets/images/icons/small-room.png");
width: 17px;
height: 16px;
}
&.icon-cog {
background: url("@/assets/images/icons/cog.png");
width: 21px;
height: 21px;
}
&.icon-chat-history {
background: url("@/assets/images/icons/chat-history.png");
width: 17px;
height: 21px;
}
&.icon-room-link {
background: url("@/assets/images/icons/room-link.png");
width: 17px;
height: 15px;
}
&.icon-zoom-more {
background: url("@/assets/images/icons/zoom-more.png");
width: 12px;
height: 22px;
}
&.icon-zoom-less {
background: url("@/assets/images/icons/zoom-less.png");
width: 12px;
height: 22px;
}
&.icon-like-room {
background: url("@/assets/images/icons/like-room.png");
width: 20px;
height: 22px;
}
&.icon-arrows {
background: url("@/assets/images/icons/arrows.png");
width: 17px;
height: 15px;
}
&.icon-camera-colormatrix {
background: url("@/assets/images/icons/camera-colormatrix.png");
width: 32px;
height: 21px;
}
&.icon-camera-composite {
background: url("@/assets/images/icons/camera-composite.png");
width: 32px;
height: 21px;
}
&.icon-pf-online {
background: url("@/assets/images/profile/icons/online.gif");
width: 40px;
height: 16px;
}
&.icon-pf-offline {
background: url("@/assets/images/profile/icons/offline.png");
width: 39px;
height: 16px;
}
&.icon-pf-tick {
background: url("@/assets/images/profile/icons/tick.png");
width: 11px;
height: 10px;
}
&.icon-group-type-0 {
background: url("@/assets/images/groups/icons/grouptype_icon_0.png");
width: 16px;
height: 16px;
}
&.icon-group-type-1 {
background: url("@/assets/images/groups/icons/grouptype_icon_1.png");
width: 16px;
height: 16px;
}
&.icon-group-type-2 {
background: url("@/assets/images/groups/icons/grouptype_icon_2.png");
width: 16px;
height: 16px;
}
&.icon-group-decorate {
background: url("@/assets/images/groups/icons/group_decorate_icon.png");
width: 15px;
height: 15px;
}
&.icon-group-member {
background: url("@/assets/images/groups/icons/group_icon_big_member.png");
width: 20px;
height: 20px;
}
&.icon-group-admin {
background: url("@/assets/images/groups/icons/group_icon_big_admin.png");
width: 20px;
height: 20px;
}
&.icon-group-owner {
background: url("@/assets/images/groups/icons/group_icon_big_owner.png");
width: 20px;
height: 20px;
}
&.icon-group-favorite {
background: url("@/assets/images/groups/icons/group_favorite.png");
width: 14px;
height: 14px;
}
&.icon-group-not-favorite {
background: url("@/assets/images/groups/icons/group_notfavorite.png");
width: 14px;
height: 14px;
}
&.icon-group-small-admin {
background: url("@/assets/images/groups/icons/group_icon_admin.png");
width: 11px;
height: 13px;
}
&.icon-group-small-not-admin {
background: url("@/assets/images/groups/icons/group_icon_not_admin.png");
width: 11px;
height: 13px;
}
&.icon-group-small-owner {
background: url("@/assets/images/groups/icons/group_icon_small_owner.png");
width: 13px;
height: 13px;
}
&.icon-navigator-info {
background: url("@/assets/images/navigator/icons/info.png");
width: 18px;
height: 18px;
}
&.icon-navigator-room-locked {
background: url("@/assets/images/navigator/icons/room_locked.png");
width: 13px;
height: 16px;
}
&.icon-navigator-room-password {
background: url("@/assets/images/navigator/icons/room_password.png");
width: 13px;
height: 16px;
}
&.icon-navigator-room-invisible {
background: url("@/assets/images/navigator/icons/room_invisible.png");
width: 13px;
height: 16px;
}
&.icon-navigator-room-group {
background: url("@/assets/images/navigator/icons/room_group.png");
width: 13px;
height: 11px;
}
&.icon-youtube-next {
background: url("@/assets/images/room-widgets/youtube-widget/next.png");
width: 21px;
height: 16px;
}
&.icon-youtube-prev {
background: url("@/assets/images/room-widgets/youtube-widget/prev.png");
width: 21px;
height: 16px;
}
&.icon-hc-banner {
background: url("@/assets/images/catalog/hc_big.png");
width: 68px;
height: 40px;
}
&.icon-set-tile {
background-image: url("@/assets/images/floorplaneditor/icon-tile-set.png");
width: 40px;
height: 40px;
}
&.icon-unset-tile {
background-image: url("@/assets/images/floorplaneditor/icon-tile-unset.png");
width: 40px;
height: 40px;
}
&.icon-increase-height {
background-image: url("@/assets/images/floorplaneditor/icon-tile-up.png");
width: 40px;
height: 40px;
}
&.icon-decrease-height {
background-image: url("@/assets/images/floorplaneditor/icon-tile-down.png");
width: 40px;
height: 40px;
}
&.icon-set-door {
background-image: url("@/assets/images/floorplaneditor/icon-door.png");
width: 40px;
height: 40px;
}
&.icon-door-direction-0 {
background-image: url("@/assets/images/floorplaneditor/door-direction-0.png");
width: 80px;
height: 45px;
}
&.icon-door-direction-1 {
background-image: url("@/assets/images/floorplaneditor/door-direction-1.png");
width: 80px;
height: 45px;
}
&.icon-door-direction-2 {
background-image: url("@/assets/images/floorplaneditor/door-direction-2.png");
width: 80px;
height: 45px;
}
&.icon-door-direction-3 {
background-image: url("@/assets/images/floorplaneditor/door-direction-3.png");
width: 80px;
height: 45px;
}
&.icon-door-direction-4 {
background-image: url("@/assets/images/floorplaneditor/door-direction-4.png");
width: 80px;
height: 45px;
}
&.icon-door-direction-5 {
background-image: url("@/assets/images/floorplaneditor/door-direction-5.png");
width: 80px;
height: 45px;
}
&.icon-door-direction-6 {
background-image: url("@/assets/images/floorplaneditor/door-direction-6.png");
width: 80px;
height: 45px;
}
&.icon-door-direction-7 {
background-image: url("@/assets/images/floorplaneditor/door-direction-7.png");
width: 80px;
height: 45px;
}
&.icon-tickets {
background-image: url("@/assets/images/icons/tickets.png");
width: 17px;
height: 17px;
}
&.icon-user {
background-image: url("@/assets/images/icons/user.png");
width: 18px;
height: 19px;
}
&.icon-loading {
background-image: url("@/assets/images/ui/loading_icon.png");
&.with-size {
width: 16px;
height: 16px;
}
}
}
}
.unique-item {
@ -916,7 +286,7 @@ body {
&.n-0 {
width: 4px;
background-position: -1px 0px;
baseackground-position: -1px 0px;
}
&.n-1 {

54
src/css/slider.css Normal file
View File

@ -0,0 +1,54 @@
.nitro-slider {
display: flex;
align-items: center;
width: 100%;
height: 25px;
.track {
height: 3px;
border-radius: $border-radius;
overflow: hidden;
&.track-0 {
background-color: $primary;
}
&.track-1 {
background-color: $muted;
}
}
.thumb {
border-radius: 50%;
width: 25px;
height: 25px;
background-color: gray;
font-size: 10px;
text-align: center;
line-height: 25px;
padding: 0 3px;
&:hover,
.active {
cursor: pointer;
}
&.active {
outline: none;
}
&.degree {
&:after {
content: '\00b0'
}
}
&.percent {
&:after {
content: '\0025'
}
}
}
}

View File

@ -134,7 +134,7 @@ const useMessengerState = () =>
{
const parser = event.getParser();
simpleAlert(`Received room invite error: ${parser.errorCode},recipients: ${parser.failedRecipients.join(',')}`, NotificationAlertType.DEFAULT, null, null, LocalizeText('friendlist.alert.title'));
simpleAlert(`Received room invite error: ${ parser.errorCode },recipients: ${ parser.failedRecipients.join(',') }`, NotificationAlertType.DEFAULT, null, null, LocalizeText('friendlist.alert.title'));
});
useEffect(() =>

File diff suppressed because it is too large Load Diff

View File

@ -2,20 +2,28 @@ import { createRoot } from 'react-dom/client';
import { App } from './App';
import './css/index.css';
import './css/NitroCardView.css';
import './css/PurseView.css';
import './css/chat/chats.css';
import './css/hotelview/HotelView.scss';
import './css/floorplan/FloorplanEditorView.css';
import './css/hotelview/HotelView.css';
import './css/icons/icons.css';
import './css/loading/loading.css';
import './css/nitrocard/NitroCardView.css';
import './css/notification/NotificationCenterView.css';
import './css/purse/PurseView.css';
import './css/room/ChatHistoryView.css';
import './css/room/RoomWidgets.css';
import './css/slider.css';
import './css/widgets/FurnitureWidgets.css';
createRoot(document.getElementById('root')).render(<App />);