@rpg-engine/long-bow 0.5.13 → 0.5.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Chat/Chat.d.ts +3 -4
- package/dist/components/ChatRevamp/ChatRevamp.d.ts +28 -0
- package/dist/components/ChatRevamp/SearchCharacter.d.ts +14 -0
- package/dist/components/Multitab/TabBody.d.ts +2 -0
- package/dist/components/TradingMenu/TradingItemRow.d.ts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/long-bow.cjs.development.js +247 -75
- package/dist/long-bow.cjs.development.js.map +1 -1
- package/dist/long-bow.cjs.production.min.js +1 -1
- package/dist/long-bow.cjs.production.min.js.map +1 -1
- package/dist/long-bow.esm.js +249 -78
- package/dist/long-bow.esm.js.map +1 -1
- package/dist/stories/ChatRevamp.stories.d.ts +6 -0
- package/package.json +2 -2
- package/src/components/Chat/Chat.tsx +16 -7
- package/src/components/ChatRevamp/ChatRevamp.tsx +121 -0
- package/src/components/ChatRevamp/SearchCharacter.tsx +163 -0
- package/src/components/Item/Inventory/ItemContainer.tsx +3 -56
- package/src/components/Multitab/Tab.tsx +3 -2
- package/src/components/Multitab/TabBody.tsx +17 -3
- package/src/components/Multitab/TabsContainer.tsx +2 -2
- package/src/components/Spellbook/mockSpells.ts +10 -5
- package/src/components/TradingMenu/TradingItemRow.tsx +58 -0
- package/src/components/TradingMenu/TradingMenu.tsx +1 -0
- package/src/index.tsx +1 -0
- package/src/mocks/itemContainer.mocks.ts +35 -31
- package/src/stories/ChatRevamp.stories.tsx +248 -0
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Meta } from '@storybook/react';
|
|
2
|
+
import { IChatRevampProps } from '../components/ChatRevamp/ChatRevamp';
|
|
3
|
+
declare const meta: Meta;
|
|
4
|
+
export default meta;
|
|
5
|
+
export declare const Default: import("@storybook/csf").AnnotatedStoryFn<import("@storybook/react").ReactFramework, IChatRevampProps>;
|
|
6
|
+
export declare const PrivateCharacters: import("@storybook/csf").AnnotatedStoryFn<import("@storybook/react").ReactFramework, IChatRevampProps>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rpg-engine/long-bow",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.15",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"typings": "dist/index.d.ts",
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
},
|
|
84
84
|
"dependencies": {
|
|
85
85
|
"@rollup/plugin-image": "^2.1.1",
|
|
86
|
-
"@rpg-engine/shared": "^0.8.
|
|
86
|
+
"@rpg-engine/shared": "^0.8.83",
|
|
87
87
|
"dayjs": "^1.11.2",
|
|
88
88
|
"font-awesome": "^4.7.0",
|
|
89
89
|
"fs-extra": "^10.1.0",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IChatMessage } from '@rpg-engine/shared';
|
|
1
|
+
import { IChatMessage, IPrivateChatMessage } from '@rpg-engine/shared';
|
|
2
2
|
import dayjs from 'dayjs';
|
|
3
3
|
import React, { useEffect, useState } from 'react';
|
|
4
4
|
import { ErrorBoundary } from 'react-error-boundary';
|
|
@@ -11,7 +11,7 @@ interface IEmitter {
|
|
|
11
11
|
name: string;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
interface IStyles {
|
|
14
|
+
export interface IStyles {
|
|
15
15
|
textColor?: string;
|
|
16
16
|
buttonColor?: string;
|
|
17
17
|
buttonBackgroundColor?: string;
|
|
@@ -20,7 +20,7 @@ interface IStyles {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
export interface IChatProps {
|
|
23
|
-
chatMessages: IChatMessage[];
|
|
23
|
+
chatMessages: IChatMessage[] | IPrivateChatMessage[];
|
|
24
24
|
onSendChatMessage: (message: string) => void;
|
|
25
25
|
onCloseButton: () => void;
|
|
26
26
|
onFocus?: () => void;
|
|
@@ -80,11 +80,20 @@ export const Chat: React.FC<IChatProps> = ({
|
|
|
80
80
|
} ${message}`;
|
|
81
81
|
};
|
|
82
82
|
|
|
83
|
-
const onRenderChatMessages = (
|
|
83
|
+
const onRenderChatMessages = (
|
|
84
|
+
chatMessages: (IChatMessage | IPrivateChatMessage)[]
|
|
85
|
+
) => {
|
|
84
86
|
return chatMessages?.length ? (
|
|
85
|
-
chatMessages?.map((
|
|
86
|
-
<Message
|
|
87
|
-
{
|
|
87
|
+
chatMessages?.map((chatMessage, index) => (
|
|
88
|
+
<Message
|
|
89
|
+
color={styles?.textColor || '#c65102'}
|
|
90
|
+
key={`${chatMessage._id}_${index}`}
|
|
91
|
+
>
|
|
92
|
+
{onRenderMessageLines(
|
|
93
|
+
chatMessage.emitter,
|
|
94
|
+
chatMessage.createdAt as string,
|
|
95
|
+
chatMessage.message
|
|
96
|
+
)}
|
|
88
97
|
</Message>
|
|
89
98
|
))
|
|
90
99
|
) : (
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ICharacter,
|
|
3
|
+
IChatMessage,
|
|
4
|
+
IPrivateChatMessage,
|
|
5
|
+
} from '@rpg-engine/shared';
|
|
6
|
+
import React, { useEffect, useState } from 'react';
|
|
7
|
+
import styled from 'styled-components';
|
|
8
|
+
import { uiColors } from '../../constants/uiColors';
|
|
9
|
+
import { Chat, IStyles } from '../Chat/Chat';
|
|
10
|
+
import { SearchCharacter } from './SearchCharacter';
|
|
11
|
+
|
|
12
|
+
export interface ITabStyles {
|
|
13
|
+
width?: string;
|
|
14
|
+
height?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type PrivateChatCharacter = Pick<ICharacter, '_id' | 'name'>;
|
|
18
|
+
|
|
19
|
+
export interface IChatRevampProps {
|
|
20
|
+
chatMessages: IChatMessage[] | IPrivateChatMessage[];
|
|
21
|
+
onSendGlobalChatMessage: (message: string) => void;
|
|
22
|
+
onCloseButton: () => void;
|
|
23
|
+
onFocus?: () => void;
|
|
24
|
+
onBlur?: () => void;
|
|
25
|
+
opacity?: number;
|
|
26
|
+
styles?: IStyles;
|
|
27
|
+
tabs: { label: string; id: string }[];
|
|
28
|
+
activeTab: string;
|
|
29
|
+
onChangeTab: (tabId: string) => void;
|
|
30
|
+
privateChatCharacters?: PrivateChatCharacter[];
|
|
31
|
+
onChangeCharacterName: (characterName: string) => void;
|
|
32
|
+
onCharacterClick?: (character: PrivateChatCharacter) => void;
|
|
33
|
+
onSendPrivateChatMessage: (message: string) => void;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const ChatRevamp = ({
|
|
37
|
+
chatMessages,
|
|
38
|
+
onSendGlobalChatMessage,
|
|
39
|
+
onChangeCharacterName,
|
|
40
|
+
onFocus,
|
|
41
|
+
onBlur,
|
|
42
|
+
onCloseButton,
|
|
43
|
+
styles,
|
|
44
|
+
tabs,
|
|
45
|
+
onChangeTab,
|
|
46
|
+
activeTab,
|
|
47
|
+
privateChatCharacters,
|
|
48
|
+
onCharacterClick,
|
|
49
|
+
onSendPrivateChatMessage,
|
|
50
|
+
}: IChatRevampProps) => {
|
|
51
|
+
const [showSearchCharacter, setShowSearchCharacter] = useState(true);
|
|
52
|
+
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
setShowSearchCharacter(true);
|
|
55
|
+
}, [activeTab]);
|
|
56
|
+
|
|
57
|
+
const isPrivate = activeTab === 'private';
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<>
|
|
61
|
+
<TabContainer>
|
|
62
|
+
{tabs.map((tab, index) => (
|
|
63
|
+
<Tab
|
|
64
|
+
key={`${tab.label}_${index}`}
|
|
65
|
+
active={tab.id === activeTab}
|
|
66
|
+
onPointerDown={() => onChangeTab(tab.id)}
|
|
67
|
+
>
|
|
68
|
+
{tab.label}
|
|
69
|
+
</Tab>
|
|
70
|
+
))}
|
|
71
|
+
</TabContainer>
|
|
72
|
+
{isPrivate && showSearchCharacter ? (
|
|
73
|
+
<SearchCharacter
|
|
74
|
+
onFocus={onFocus}
|
|
75
|
+
onBlur={onBlur}
|
|
76
|
+
onChangeCharacterName={onChangeCharacterName}
|
|
77
|
+
styles={styles}
|
|
78
|
+
recentCharacters={privateChatCharacters}
|
|
79
|
+
setShowSearchCharacter={setShowSearchCharacter}
|
|
80
|
+
onCharacterClick={onCharacterClick}
|
|
81
|
+
/>
|
|
82
|
+
) : (
|
|
83
|
+
<Chat
|
|
84
|
+
chatMessages={chatMessages}
|
|
85
|
+
onSendChatMessage={
|
|
86
|
+
isPrivate ? onSendPrivateChatMessage : onSendGlobalChatMessage
|
|
87
|
+
}
|
|
88
|
+
sendMessage={true}
|
|
89
|
+
onCloseButton={onCloseButton}
|
|
90
|
+
styles={styles}
|
|
91
|
+
onFocus={onFocus}
|
|
92
|
+
onBlur={onBlur}
|
|
93
|
+
/>
|
|
94
|
+
)}
|
|
95
|
+
</>
|
|
96
|
+
);
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const TabContainer = styled.div`
|
|
100
|
+
width: 100%;
|
|
101
|
+
display: flex;
|
|
102
|
+
gap: 10px;
|
|
103
|
+
`;
|
|
104
|
+
|
|
105
|
+
const Tab = styled.button<{ active: boolean }>`
|
|
106
|
+
width: 120px;
|
|
107
|
+
color: white;
|
|
108
|
+
font-size: 0.8rem;
|
|
109
|
+
all: unset;
|
|
110
|
+
padding: 0.6rem;
|
|
111
|
+
font-size: 0.8rem;
|
|
112
|
+
|
|
113
|
+
border-radius: 5px 5px 0 0;
|
|
114
|
+
border-width: 0.25rem 0.25rem 0 0.25rem;
|
|
115
|
+
border-style: solid;
|
|
116
|
+
border-color: ${props => (props.active ? '#c65102' : uiColors.gray)};
|
|
117
|
+
|
|
118
|
+
background-color: ${props =>
|
|
119
|
+
props.active ? uiColors.orange : 'transparent'};
|
|
120
|
+
color: ${props => (props.active ? 'white' : uiColors.raisinBlack)};
|
|
121
|
+
`;
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { RxMagnifyingGlass } from 'react-icons/rx';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
import { uiColors } from '../../constants/uiColors';
|
|
5
|
+
import { uiFonts } from '../../constants/uiFonts';
|
|
6
|
+
import { IStyles } from '../Chat/Chat';
|
|
7
|
+
import { Column } from '../shared/Column';
|
|
8
|
+
import type { PrivateChatCharacter } from './ChatRevamp';
|
|
9
|
+
|
|
10
|
+
interface ISearchCharacterProps {
|
|
11
|
+
onFocus?: () => void;
|
|
12
|
+
onBlur?: () => void;
|
|
13
|
+
onChangeCharacterName: (characterName: string) => void;
|
|
14
|
+
styles?: IStyles;
|
|
15
|
+
recentCharacters?: PrivateChatCharacter[];
|
|
16
|
+
setShowSearchCharacter: (show: boolean) => void;
|
|
17
|
+
onCharacterClick?: (character: PrivateChatCharacter) => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const SearchCharacter = ({
|
|
21
|
+
onChangeCharacterName,
|
|
22
|
+
onBlur,
|
|
23
|
+
onFocus,
|
|
24
|
+
recentCharacters,
|
|
25
|
+
setShowSearchCharacter,
|
|
26
|
+
onCharacterClick,
|
|
27
|
+
styles = {
|
|
28
|
+
textColor: '#c65102',
|
|
29
|
+
buttonColor: '#005b96',
|
|
30
|
+
buttonBackgroundColor: 'rgba(0,0,0,.2)',
|
|
31
|
+
width: '80%',
|
|
32
|
+
height: 'auto',
|
|
33
|
+
},
|
|
34
|
+
}: ISearchCharacterProps) => {
|
|
35
|
+
const [characterName, setCharacterName] = useState('');
|
|
36
|
+
|
|
37
|
+
const handleSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => {
|
|
38
|
+
event.preventDefault();
|
|
39
|
+
if (!characterName || characterName.trim() === '') return;
|
|
40
|
+
onChangeCharacterName(characterName);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const handleCharacterClick = (
|
|
44
|
+
character: PrivateChatCharacter
|
|
45
|
+
) => {
|
|
46
|
+
if (!onCharacterClick) return;
|
|
47
|
+
setCharacterName('');
|
|
48
|
+
onCharacterClick(character);
|
|
49
|
+
setShowSearchCharacter(false);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<SearchCharacterContainer
|
|
54
|
+
width={styles?.width || '80%'}
|
|
55
|
+
height={styles?.height || 'auto'}
|
|
56
|
+
>
|
|
57
|
+
<Form onSubmit={handleSubmit}>
|
|
58
|
+
<Column flex={70}>
|
|
59
|
+
<TextField
|
|
60
|
+
value={characterName}
|
|
61
|
+
id="inputCharacterName"
|
|
62
|
+
onChange={e => {
|
|
63
|
+
setCharacterName(e.target.value);
|
|
64
|
+
onChangeCharacterName(e.target.value);
|
|
65
|
+
}}
|
|
66
|
+
height={20}
|
|
67
|
+
type="text"
|
|
68
|
+
autoComplete="off"
|
|
69
|
+
onFocus={onFocus}
|
|
70
|
+
onBlur={onBlur}
|
|
71
|
+
onPointerDown={onFocus}
|
|
72
|
+
autoFocus
|
|
73
|
+
/>
|
|
74
|
+
</Column>
|
|
75
|
+
<Column justifyContent="flex-end">
|
|
76
|
+
<SearchButton
|
|
77
|
+
buttonColor={styles?.buttonColor || '#005b96'}
|
|
78
|
+
buttonBackgroundColor={
|
|
79
|
+
styles?.buttonBackgroundColor || 'rgba(0,0,0,.5)'
|
|
80
|
+
}
|
|
81
|
+
id="chat-send-button"
|
|
82
|
+
style={{ borderRadius: '20%' }}
|
|
83
|
+
>
|
|
84
|
+
<RxMagnifyingGlass size={15} />
|
|
85
|
+
</SearchButton>
|
|
86
|
+
</Column>
|
|
87
|
+
</Form>
|
|
88
|
+
|
|
89
|
+
{recentCharacters && recentCharacters.length > 0 && (
|
|
90
|
+
<ListContainer>
|
|
91
|
+
{recentCharacters.map(character => (
|
|
92
|
+
<ListElement onPointerDown={() => handleCharacterClick(character)} key={character._id}>
|
|
93
|
+
{character.name}
|
|
94
|
+
</ListElement>
|
|
95
|
+
))}
|
|
96
|
+
</ListContainer>
|
|
97
|
+
)}
|
|
98
|
+
</SearchCharacterContainer>
|
|
99
|
+
);
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
interface IContainerProps {
|
|
103
|
+
width: string;
|
|
104
|
+
height: string;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
interface IButtonProps {
|
|
108
|
+
buttonColor: string;
|
|
109
|
+
buttonBackgroundColor: string;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const SearchCharacterContainer = styled.div<IContainerProps>`
|
|
113
|
+
height: ${props => props.height};
|
|
114
|
+
width: ${({ width }) => width};
|
|
115
|
+
padding: 10px;
|
|
116
|
+
background-color: rgba(0, 0, 0, 0.2);
|
|
117
|
+
height: auto;
|
|
118
|
+
`;
|
|
119
|
+
|
|
120
|
+
const Form = styled.form`
|
|
121
|
+
display: flex;
|
|
122
|
+
width: 100%;
|
|
123
|
+
justify-content: center;
|
|
124
|
+
align-items: center;
|
|
125
|
+
`;
|
|
126
|
+
|
|
127
|
+
const TextField = styled.input`
|
|
128
|
+
width: 100%;
|
|
129
|
+
background-color: rgba(0, 0, 0, 0.25) !important;
|
|
130
|
+
border: none !important;
|
|
131
|
+
max-height: 28px !important;
|
|
132
|
+
`;
|
|
133
|
+
|
|
134
|
+
const SearchButton = styled.button<IButtonProps>`
|
|
135
|
+
color: ${({ buttonColor }) => buttonColor};
|
|
136
|
+
background-color: ${({ buttonBackgroundColor }) => buttonBackgroundColor};
|
|
137
|
+
width: 28px;
|
|
138
|
+
height: 28px;
|
|
139
|
+
border: none !important;
|
|
140
|
+
`;
|
|
141
|
+
|
|
142
|
+
const ListContainer = styled.ul`
|
|
143
|
+
border: none;
|
|
144
|
+
overflow-y: scroll;
|
|
145
|
+
list-style: none;
|
|
146
|
+
padding: 0;
|
|
147
|
+
`;
|
|
148
|
+
|
|
149
|
+
const ListElement = styled.li`
|
|
150
|
+
margin: 0.5rem 0 !important;
|
|
151
|
+
font-size: ${uiFonts.size.small};
|
|
152
|
+
|
|
153
|
+
&:hover {
|
|
154
|
+
color: #ff0;
|
|
155
|
+
background-color: ${uiColors.darkGray};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
button {
|
|
159
|
+
all: unset;
|
|
160
|
+
}
|
|
161
|
+
`;
|
|
162
|
+
|
|
163
|
+
|
|
@@ -13,7 +13,6 @@ import { ItemQuantitySelector } from './ItemQuantitySelector';
|
|
|
13
13
|
|
|
14
14
|
import { IPosition } from '../../../types/eventTypes';
|
|
15
15
|
import ModalPortal from '../../Abstractions/ModalPortal';
|
|
16
|
-
import SelectArrow from '../../Arrow/SelectArrow';
|
|
17
16
|
import { ShortcutsSetter } from '../../Shortcuts/ShortcutsSetter';
|
|
18
17
|
import { ItemSlot } from './ItemSlot';
|
|
19
18
|
|
|
@@ -82,15 +81,12 @@ export const ItemContainer: React.FC<IItemContainerProps> = ({
|
|
|
82
81
|
onPositionChangeEnd,
|
|
83
82
|
onPositionChangeStart,
|
|
84
83
|
}) => {
|
|
85
|
-
const MAX_SLOTS_PER_PAGE = 20;
|
|
86
84
|
const [quantitySelect, setQuantitySelect] = useState({
|
|
87
85
|
isOpen: false,
|
|
88
86
|
maxQuantity: 1,
|
|
89
87
|
callback: (_quantity: number) => { },
|
|
90
88
|
});
|
|
91
89
|
const [settingShortcutIndex, setSettingShortcutIndex] = useState(-1);
|
|
92
|
-
const [currentPage, setCurrentPage] = useState(1);
|
|
93
|
-
const totalPages = Math.ceil(itemContainer.slotQty / MAX_SLOTS_PER_PAGE);
|
|
94
90
|
|
|
95
91
|
const handleSetShortcut = (item: IItem, index: number) => {
|
|
96
92
|
if (item.type === ItemType.Consumable || item.type === ItemType.Tool) {
|
|
@@ -100,11 +96,8 @@ export const ItemContainer: React.FC<IItemContainerProps> = ({
|
|
|
100
96
|
|
|
101
97
|
const onRenderSlots = () => {
|
|
102
98
|
const slots = [];
|
|
103
|
-
const start = (currentPage - 1) * MAX_SLOTS_PER_PAGE;
|
|
104
|
-
const end = start + MAX_SLOTS_PER_PAGE;
|
|
105
99
|
|
|
106
|
-
for (let i =
|
|
107
|
-
console.log(itemContainer)
|
|
100
|
+
for (let i = 0; i < itemContainer.slotQty; i++) {
|
|
108
101
|
slots.push(
|
|
109
102
|
<ItemSlot
|
|
110
103
|
isContextMenuDisabled={disableContextMenu}
|
|
@@ -163,14 +156,6 @@ export const ItemContainer: React.FC<IItemContainerProps> = ({
|
|
|
163
156
|
return slots;
|
|
164
157
|
};
|
|
165
158
|
|
|
166
|
-
const goToNextPage = () => {
|
|
167
|
-
setCurrentPage(current => Math.min(current + 1, totalPages));
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
const goToPreviousPage = () => {
|
|
171
|
-
setCurrentPage(current => Math.max(current - 1, 1));
|
|
172
|
-
};
|
|
173
|
-
|
|
174
159
|
return (
|
|
175
160
|
<>
|
|
176
161
|
<SlotsContainer
|
|
@@ -196,32 +181,6 @@ export const ItemContainer: React.FC<IItemContainerProps> = ({
|
|
|
196
181
|
<ItemsContainer className="item-container-body">
|
|
197
182
|
{onRenderSlots()}
|
|
198
183
|
</ItemsContainer>
|
|
199
|
-
{totalPages > 1 && (
|
|
200
|
-
<ArrowContainer>
|
|
201
|
-
{currentPage > 1 && (
|
|
202
|
-
<SelectArrow
|
|
203
|
-
className='arrow .arrow-up'
|
|
204
|
-
direction="left"
|
|
205
|
-
onPointerDown={() => {
|
|
206
|
-
if (currentPage > 1) {
|
|
207
|
-
goToPreviousPage();
|
|
208
|
-
}
|
|
209
|
-
}}
|
|
210
|
-
/>
|
|
211
|
-
)}
|
|
212
|
-
{currentPage < totalPages && (
|
|
213
|
-
<SelectArrow
|
|
214
|
-
className='arrow .arrow-down'
|
|
215
|
-
direction="right"
|
|
216
|
-
onPointerDown={() => {
|
|
217
|
-
if (currentPage < totalPages) {
|
|
218
|
-
goToNextPage();
|
|
219
|
-
}
|
|
220
|
-
}}
|
|
221
|
-
/>
|
|
222
|
-
)}
|
|
223
|
-
</ArrowContainer>
|
|
224
|
-
)}
|
|
225
184
|
</SlotsContainer>
|
|
226
185
|
{quantitySelect.isOpen && (
|
|
227
186
|
<ModalPortal>
|
|
@@ -256,6 +215,8 @@ const ItemsContainer = styled.div`
|
|
|
256
215
|
display: flex;
|
|
257
216
|
justify-content: center;
|
|
258
217
|
flex-wrap: wrap;
|
|
218
|
+
max-height: 270px; /* Defina a altura máxima desejada */
|
|
219
|
+
overflow-y: auto; /* Adicione uma barra de rolagem vertical quando necessário */
|
|
259
220
|
`;
|
|
260
221
|
|
|
261
222
|
const QuantitySelectorContainer = styled.div`
|
|
@@ -270,17 +231,3 @@ const QuantitySelectorContainer = styled.div`
|
|
|
270
231
|
align-items: center;
|
|
271
232
|
background-color: rgba(0, 0, 0, 0.5);
|
|
272
233
|
`;
|
|
273
|
-
|
|
274
|
-
const ArrowContainer = styled.div`
|
|
275
|
-
margin-top: 10px;
|
|
276
|
-
margin-bottom: 30px;
|
|
277
|
-
/* Aplica a margem ao primeiro span (seta para a esquerda) */
|
|
278
|
-
span:first-child {
|
|
279
|
-
margin-left: 20px;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
/* Aplica a margem ao último span (seta para a direita) */
|
|
283
|
-
span:last-child {
|
|
284
|
-
margin-right: 20px;
|
|
285
|
-
}
|
|
286
|
-
`;
|
|
@@ -39,6 +39,8 @@ const CustomTab = styled.div<ICustomTab>`
|
|
|
39
39
|
border-left: 0.25rem solid rgba(0, 0, 0, 0.25);
|
|
40
40
|
border-right: 0.25rem solid rgba(0, 0, 0, 0.25);
|
|
41
41
|
border-top: 0.25rem solid rgba(0, 0, 0, 0.25);
|
|
42
|
+
border-bottom: ${props =>
|
|
43
|
+
props.activeTab ? '' : '0.25rem solid rgba(0, 0, 0, 0.25)'};
|
|
42
44
|
background: ${props => (props.activeTab ? '#4E4A4E' : '#2b292b')};
|
|
43
45
|
}
|
|
44
46
|
|
|
@@ -46,6 +48,7 @@ const CustomTab = styled.div<ICustomTab>`
|
|
|
46
48
|
border-left: 0.25rem solid #996d55;
|
|
47
49
|
border-right: 0.25rem solid #996d55;
|
|
48
50
|
border-top: 0.25rem solid #996d55;
|
|
51
|
+
border-bottom: ${props => (props.activeTab ? '' : '0.25rem solid #996d55')};
|
|
49
52
|
background: ${props => (props.activeTab ? '#BF886A' : '#B67051')};
|
|
50
53
|
}
|
|
51
54
|
|
|
@@ -59,8 +62,6 @@ const CustomTab = styled.div<ICustomTab>`
|
|
|
59
62
|
|
|
60
63
|
border-radius: 5px 5px 0 0;
|
|
61
64
|
|
|
62
|
-
z-index: ${props => (props.activeTab ? 1 : -1)};
|
|
63
|
-
|
|
64
65
|
position: relative;
|
|
65
66
|
top: 0.3rem;
|
|
66
67
|
`;
|
|
@@ -1,13 +1,27 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import styled from 'styled-components';
|
|
3
|
+
import { IStyles } from '../Chat/Chat';
|
|
3
4
|
|
|
4
5
|
interface IProps {
|
|
5
6
|
id: string;
|
|
6
7
|
children: React.ReactNode;
|
|
8
|
+
styles?: IStyles;
|
|
7
9
|
}
|
|
8
10
|
|
|
9
|
-
export const TabBody: React.FC<IProps> = ({ id, children }) => {
|
|
10
|
-
return
|
|
11
|
+
export const TabBody: React.FC<IProps> = ({ id, children, styles }) => {
|
|
12
|
+
return (
|
|
13
|
+
<Container styles={styles} data-tab-id={id}>
|
|
14
|
+
{children}
|
|
15
|
+
</Container>
|
|
16
|
+
);
|
|
11
17
|
};
|
|
12
18
|
|
|
13
|
-
|
|
19
|
+
interface IContainerProps {
|
|
20
|
+
styles?: IStyles;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const Container = styled.div<IContainerProps>`
|
|
24
|
+
width: 100%;
|
|
25
|
+
height: ${props => props.styles?.height || 'auto'};
|
|
26
|
+
overflow-y: auto;
|
|
27
|
+
`;
|
|
@@ -42,9 +42,9 @@ export const TabsContainer: React.FC<ITabsContainer> = ({
|
|
|
42
42
|
|
|
43
43
|
const onGetContainerType = () => {
|
|
44
44
|
switch (type) {
|
|
45
|
-
case
|
|
45
|
+
case MultitabType.Brown:
|
|
46
46
|
return RPGUIContainerTypes.FramedGold;
|
|
47
|
-
case
|
|
47
|
+
case MultitabType.Gray:
|
|
48
48
|
return RPGUIContainerTypes.Framed;
|
|
49
49
|
default:
|
|
50
50
|
return RPGUIContainerTypes.Framed;
|
|
@@ -22,7 +22,8 @@ export const mockSpells: ISpell[] = [
|
|
|
22
22
|
castingAnimationKey: AnimationEffectKeys.SkillLevelUp,
|
|
23
23
|
targetHitAnimationKey: AnimationEffectKeys.Rooted,
|
|
24
24
|
projectileAnimationKey: AnimationEffectKeys.Energy,
|
|
25
|
-
usableEffect: () => {},
|
|
25
|
+
usableEffect: () => { },
|
|
26
|
+
onlyPremiumAccountType: [],
|
|
26
27
|
},
|
|
27
28
|
{
|
|
28
29
|
key: (SpellsBlueprint.ArrowCreationSpell + '2') as SpellsBlueprint,
|
|
@@ -40,7 +41,8 @@ export const mockSpells: ISpell[] = [
|
|
|
40
41
|
castingAnimationKey: AnimationEffectKeys.SkillLevelUp,
|
|
41
42
|
targetHitAnimationKey: AnimationEffectKeys.Rooted,
|
|
42
43
|
projectileAnimationKey: AnimationEffectKeys.Energy,
|
|
43
|
-
usableEffect: () => {},
|
|
44
|
+
usableEffect: () => { },
|
|
45
|
+
onlyPremiumAccountType: [],
|
|
44
46
|
},
|
|
45
47
|
{
|
|
46
48
|
key: (SpellsBlueprint.ArrowCreationSpell + '3') as SpellsBlueprint,
|
|
@@ -58,7 +60,8 @@ export const mockSpells: ISpell[] = [
|
|
|
58
60
|
castingAnimationKey: AnimationEffectKeys.SkillLevelUp,
|
|
59
61
|
targetHitAnimationKey: AnimationEffectKeys.Rooted,
|
|
60
62
|
projectileAnimationKey: AnimationEffectKeys.Energy,
|
|
61
|
-
usableEffect: () => {},
|
|
63
|
+
usableEffect: () => { },
|
|
64
|
+
onlyPremiumAccountType: [],
|
|
62
65
|
},
|
|
63
66
|
{
|
|
64
67
|
key: (SpellsBlueprint.ArrowCreationSpell + '4') as SpellsBlueprint,
|
|
@@ -76,7 +79,8 @@ export const mockSpells: ISpell[] = [
|
|
|
76
79
|
castingAnimationKey: AnimationEffectKeys.SkillLevelUp,
|
|
77
80
|
targetHitAnimationKey: AnimationEffectKeys.Rooted,
|
|
78
81
|
projectileAnimationKey: AnimationEffectKeys.Energy,
|
|
79
|
-
usableEffect: () => {},
|
|
82
|
+
usableEffect: () => { },
|
|
83
|
+
onlyPremiumAccountType: [],
|
|
80
84
|
},
|
|
81
85
|
{
|
|
82
86
|
key: (SpellsBlueprint.ArrowCreationSpell + '5') as SpellsBlueprint,
|
|
@@ -94,6 +98,7 @@ export const mockSpells: ISpell[] = [
|
|
|
94
98
|
castingAnimationKey: AnimationEffectKeys.SkillLevelUp,
|
|
95
99
|
targetHitAnimationKey: AnimationEffectKeys.Rooted,
|
|
96
100
|
projectileAnimationKey: AnimationEffectKeys.Energy,
|
|
97
|
-
usableEffect: () => {},
|
|
101
|
+
usableEffect: () => { },
|
|
102
|
+
onlyPremiumAccountType: [],
|
|
98
103
|
},
|
|
99
104
|
];
|
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
getItemTextureKeyPath,
|
|
3
3
|
IEquipmentSet,
|
|
4
4
|
ITradeResponseItem,
|
|
5
|
+
UserAccountTypes,
|
|
5
6
|
} from '@rpg-engine/shared';
|
|
6
7
|
import capitalize from 'lodash/capitalize';
|
|
7
8
|
import React from 'react';
|
|
@@ -23,6 +24,7 @@ export interface ITradeComponentProps {
|
|
|
23
24
|
selectedQty: number;
|
|
24
25
|
equipmentSet?: IEquipmentSet | null;
|
|
25
26
|
scale?: number;
|
|
27
|
+
isBuy?: boolean;
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
const outerQty = 10;
|
|
@@ -35,6 +37,7 @@ export const TradingItemRow: React.FC<ITradeComponentProps> = ({
|
|
|
35
37
|
selectedQty,
|
|
36
38
|
equipmentSet,
|
|
37
39
|
scale,
|
|
40
|
+
isBuy,
|
|
38
41
|
}) => {
|
|
39
42
|
const onLeftClick = (qty = 1) => {
|
|
40
43
|
onQuantityChange(traderItem, Math.max(0, selectedQty - qty));
|
|
@@ -47,6 +50,46 @@ export const TradingItemRow: React.FC<ITradeComponentProps> = ({
|
|
|
47
50
|
);
|
|
48
51
|
};
|
|
49
52
|
|
|
53
|
+
const renderAccountTypeIndicator = () => {
|
|
54
|
+
if (isBuy && traderItem.canBePurchasedOnlyByPremiumPlans) {
|
|
55
|
+
return traderItem.canBePurchasedOnlyByPremiumPlans.map(accountType => {
|
|
56
|
+
if (accountType !== UserAccountTypes.Free) {
|
|
57
|
+
let backgroundColor;
|
|
58
|
+
let textColor = 'black';
|
|
59
|
+
|
|
60
|
+
switch (accountType) {
|
|
61
|
+
case UserAccountTypes.PremiumBronze:
|
|
62
|
+
backgroundColor = '#CD7F32';
|
|
63
|
+
break;
|
|
64
|
+
case UserAccountTypes.PremiumSilver:
|
|
65
|
+
backgroundColor = '#C0C0C0';
|
|
66
|
+
break;
|
|
67
|
+
case UserAccountTypes.PremiumGold:
|
|
68
|
+
backgroundColor = '#FFD700';
|
|
69
|
+
break;
|
|
70
|
+
case UserAccountTypes.PremiumUltimate:
|
|
71
|
+
backgroundColor = '#002E99';
|
|
72
|
+
break;
|
|
73
|
+
default:
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<PremiumLabel
|
|
79
|
+
backgroundColor={backgroundColor}
|
|
80
|
+
textColor={textColor}
|
|
81
|
+
key={accountType}
|
|
82
|
+
>
|
|
83
|
+
{capitalize(accountType) + ' PA'}
|
|
84
|
+
</PremiumLabel>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return null;
|
|
91
|
+
};
|
|
92
|
+
|
|
50
93
|
return (
|
|
51
94
|
<ItemWrapper>
|
|
52
95
|
<ItemIconContainer>
|
|
@@ -84,6 +127,7 @@ export const TradingItemRow: React.FC<ITradeComponentProps> = ({
|
|
|
84
127
|
</Ellipsis>
|
|
85
128
|
</p>
|
|
86
129
|
<p>${traderItem.price}</p>
|
|
130
|
+
<p>{renderAccountTypeIndicator()}</p>
|
|
87
131
|
</NameValue>
|
|
88
132
|
</ItemNameContainer>
|
|
89
133
|
<QuantityContainer>
|
|
@@ -121,6 +165,20 @@ export const TradingItemRow: React.FC<ITradeComponentProps> = ({
|
|
|
121
165
|
);
|
|
122
166
|
};
|
|
123
167
|
|
|
168
|
+
const PremiumLabel = styled.span<{
|
|
169
|
+
backgroundColor: string;
|
|
170
|
+
textColor: string;
|
|
171
|
+
}>`
|
|
172
|
+
background-color: ${({ backgroundColor }) => backgroundColor};
|
|
173
|
+
color: ${({ textColor }) => textColor};
|
|
174
|
+
font-weight: bold;
|
|
175
|
+
padding: 2px 5px;
|
|
176
|
+
border-radius: 5px;
|
|
177
|
+
margin-right: 5px;
|
|
178
|
+
margin-bottom: 5px;
|
|
179
|
+
display: inline-block;
|
|
180
|
+
`;
|
|
181
|
+
|
|
124
182
|
const StyledArrow = styled(SelectArrow)`
|
|
125
183
|
margin: 40px;
|
|
126
184
|
`;
|