@rpg-engine/long-bow 0.8.29 → 0.8.30
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/Item/Inventory/ItemSlotQuality.d.ts +2 -0
- package/dist/long-bow.cjs.development.js +273 -218
- 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 +274 -219
- package/dist/long-bow.esm.js.map +1 -1
- package/package.json +2 -2
- package/src/components/InformationCenter/InformationCenter.tsx +19 -5
- package/src/components/InformationCenter/sections/bestiary/InformationCenterBestiarySection.tsx +28 -26
- package/src/components/InformationCenter/sections/bestiary/InformationCenterNPCDetails.tsx +7 -31
- package/src/components/InformationCenter/sections/items/InformationCenterItemsSection.tsx +21 -26
- package/src/components/InformationCenter/shared/BaseInformationDetails.tsx +11 -34
- package/src/components/Item/Cards/ItemInfo.tsx +18 -1
- package/src/components/Item/Inventory/ItemSlot.tsx +15 -3
- package/src/components/Item/Inventory/ItemSlotQuality.ts +18 -0
- package/src/components/Item/Inventory/ItemSlotRenderer.tsx +6 -2
- package/src/components/shared/Collapsible/Collapsible.tsx +1 -1
- package/src/mocks/itemContainer.mocks.ts +7 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rpg-engine/long-bow",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.30",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"typings": "dist/index.d.ts",
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"dependencies": {
|
|
85
85
|
"@capacitor/core": "^6.1.0",
|
|
86
86
|
"@rollup/plugin-image": "^2.1.1",
|
|
87
|
-
"@rpg-engine/shared": "^0.
|
|
87
|
+
"@rpg-engine/shared": "^0.9.104",
|
|
88
88
|
"dayjs": "^1.11.2",
|
|
89
89
|
"font-awesome": "^4.7.0",
|
|
90
90
|
"fs-extra": "^10.1.0",
|
|
@@ -9,9 +9,9 @@ import {
|
|
|
9
9
|
} from '@rpg-engine/shared';
|
|
10
10
|
import { DraggableContainer } from '../DraggableContainer';
|
|
11
11
|
import { InternalTabs } from '../InternalTabs/InternalTabs';
|
|
12
|
-
import { RPGUIContainerTypes } from '../RPGUI/RPGUIContainer';
|
|
13
12
|
import { InformationCenterBestiarySection } from './sections/bestiary/InformationCenterBestiarySection';
|
|
14
13
|
import { InformationCenterFAQSection } from './sections/faq/InformationCenterFaqSection';
|
|
14
|
+
import { InformationCenterItemDetails } from './sections/items/InformationCenterItemDetails';
|
|
15
15
|
import { InformationCenterItemsSection } from './sections/items/InformationCenterItemsSection';
|
|
16
16
|
import { InformationCenterTutorialsSection } from './sections/tutorials/InformationCenterTutorialsSection';
|
|
17
17
|
|
|
@@ -47,6 +47,10 @@ export const InformationCenter: React.FC<IInformationCenterProps> = ({
|
|
|
47
47
|
initialSearchQuery = '',
|
|
48
48
|
}) => {
|
|
49
49
|
const [activeTab, setActiveTab] = useState('bestiary');
|
|
50
|
+
const [
|
|
51
|
+
selectedItem,
|
|
52
|
+
setSelectedItem,
|
|
53
|
+
] = useState<IInformationCenterItem | null>(null);
|
|
50
54
|
|
|
51
55
|
if (loading) {
|
|
52
56
|
return <LoadingMessage>Loading...</LoadingMessage>;
|
|
@@ -113,10 +117,7 @@ export const InformationCenter: React.FC<IInformationCenterProps> = ({
|
|
|
113
117
|
];
|
|
114
118
|
|
|
115
119
|
return (
|
|
116
|
-
<DraggableContainer
|
|
117
|
-
title="Information Center"
|
|
118
|
-
type={RPGUIContainerTypes.Framed}
|
|
119
|
-
>
|
|
120
|
+
<DraggableContainer title="Information Center">
|
|
120
121
|
<Container>
|
|
121
122
|
<InternalTabs
|
|
122
123
|
tabs={tabs}
|
|
@@ -128,6 +129,19 @@ export const InformationCenter: React.FC<IInformationCenterProps> = ({
|
|
|
128
129
|
borderColor="#f59e0b"
|
|
129
130
|
hoverColor="#fef3c7"
|
|
130
131
|
/>
|
|
132
|
+
{selectedItem && (
|
|
133
|
+
<InformationCenterItemDetails
|
|
134
|
+
item={selectedItem}
|
|
135
|
+
itemsAtlasJSON={itemsAtlasJSON}
|
|
136
|
+
itemsAtlasIMG={itemsAtlasIMG}
|
|
137
|
+
droppedBy={bestiaryItems.filter(npc =>
|
|
138
|
+
npc.loots?.some(
|
|
139
|
+
loot => loot.itemBlueprintKey === selectedItem.key
|
|
140
|
+
)
|
|
141
|
+
)}
|
|
142
|
+
onBack={() => setSelectedItem(null)}
|
|
143
|
+
/>
|
|
144
|
+
)}
|
|
131
145
|
</Container>
|
|
132
146
|
</DraggableContainer>
|
|
133
147
|
);
|
package/src/components/InformationCenter/sections/bestiary/InformationCenterBestiarySection.tsx
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
IInformationCenterNPC,
|
|
3
|
-
NPCAlignment,
|
|
4
|
-
isMobileOrTablet,
|
|
5
|
-
} from '@rpg-engine/shared';
|
|
1
|
+
import { IInformationCenterNPC, NPCAlignment } from '@rpg-engine/shared';
|
|
6
2
|
import React, { useMemo, useState } from 'react';
|
|
7
3
|
import styled from 'styled-components';
|
|
8
4
|
import { IOptionsProps } from '../../../Dropdown';
|
|
@@ -12,7 +8,6 @@ import { InformationCenterCell } from '../../InformationCenterCell';
|
|
|
12
8
|
import { formatItemType } from '../items/InformationCenterItemsSection';
|
|
13
9
|
import { InformationCenterNPCDetails } from './InformationCenterNPCDetails';
|
|
14
10
|
import { InformationCenterNPCTooltip } from './InformationCenterNPCTooltip';
|
|
15
|
-
|
|
16
11
|
interface IBestiarySectionProps {
|
|
17
12
|
bestiaryItems: IInformationCenterNPC[];
|
|
18
13
|
itemsAtlasJSON: Record<string, any>;
|
|
@@ -36,7 +31,6 @@ export const InformationCenterBestiarySection: React.FC<IBestiarySectionProps> =
|
|
|
36
31
|
initialSearchQuery,
|
|
37
32
|
tabId,
|
|
38
33
|
}) => {
|
|
39
|
-
const isMobile = isMobileOrTablet();
|
|
40
34
|
const [searchQuery, setSearchQuery] = useState(initialSearchQuery);
|
|
41
35
|
const [tooltipData, setTooltipData] = useState<{
|
|
42
36
|
npc: IInformationCenterNPC;
|
|
@@ -46,12 +40,13 @@ export const InformationCenterBestiarySection: React.FC<IBestiarySectionProps> =
|
|
|
46
40
|
selectedMonster,
|
|
47
41
|
setSelectedMonster,
|
|
48
42
|
] = useState<IInformationCenterNPC | null>(null);
|
|
43
|
+
const [isTouchDevice] = useState('ontouchstart' in window);
|
|
49
44
|
|
|
50
45
|
const handleMouseEnter = (
|
|
51
46
|
monster: IInformationCenterNPC,
|
|
52
47
|
event: React.MouseEvent
|
|
53
48
|
) => {
|
|
54
|
-
if (!
|
|
49
|
+
if (!isTouchDevice && !selectedMonster) {
|
|
55
50
|
setTooltipData({
|
|
56
51
|
npc: monster,
|
|
57
52
|
position: { x: event.clientX, y: event.clientY },
|
|
@@ -60,13 +55,13 @@ export const InformationCenterBestiarySection: React.FC<IBestiarySectionProps> =
|
|
|
60
55
|
};
|
|
61
56
|
|
|
62
57
|
const handleMouseLeave = () => {
|
|
63
|
-
if (!
|
|
58
|
+
if (!isTouchDevice) {
|
|
64
59
|
setTooltipData(null);
|
|
65
60
|
}
|
|
66
61
|
};
|
|
67
62
|
|
|
68
63
|
const handleMouseMove = (event: React.MouseEvent) => {
|
|
69
|
-
if (!
|
|
64
|
+
if (!isTouchDevice && tooltipData) {
|
|
70
65
|
setTooltipData({
|
|
71
66
|
...tooltipData,
|
|
72
67
|
position: { x: event.clientX, y: event.clientY },
|
|
@@ -78,9 +73,18 @@ export const InformationCenterBestiarySection: React.FC<IBestiarySectionProps> =
|
|
|
78
73
|
monster: IInformationCenterNPC,
|
|
79
74
|
event: React.TouchEvent
|
|
80
75
|
) => {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
76
|
+
if (isTouchDevice) {
|
|
77
|
+
event.preventDefault();
|
|
78
|
+
const touch = event.touches[0];
|
|
79
|
+
if (tooltipData?.npc.id === monster.id) {
|
|
80
|
+
setTooltipData(null);
|
|
81
|
+
} else {
|
|
82
|
+
setTooltipData({
|
|
83
|
+
npc: monster,
|
|
84
|
+
position: { x: touch.clientX, y: touch.clientY },
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
84
88
|
};
|
|
85
89
|
|
|
86
90
|
const handleMonsterClick = (monster: IInformationCenterNPC) => {
|
|
@@ -166,7 +170,7 @@ export const InformationCenterBestiarySection: React.FC<IBestiarySectionProps> =
|
|
|
166
170
|
dependencies={[selectedBestiaryCategory]}
|
|
167
171
|
itemHeight="180px"
|
|
168
172
|
/>
|
|
169
|
-
{
|
|
173
|
+
{tooltipData && (
|
|
170
174
|
<Portal>
|
|
171
175
|
<TooltipWrapper
|
|
172
176
|
style={{
|
|
@@ -184,18 +188,16 @@ export const InformationCenterBestiarySection: React.FC<IBestiarySectionProps> =
|
|
|
184
188
|
</Portal>
|
|
185
189
|
)}
|
|
186
190
|
{selectedMonster && (
|
|
187
|
-
<
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
/>
|
|
198
|
-
</Portal>
|
|
191
|
+
<InformationCenterNPCDetails
|
|
192
|
+
npc={selectedMonster}
|
|
193
|
+
itemsAtlasJSON={itemsAtlasJSON}
|
|
194
|
+
itemsAtlasIMG={itemsAtlasIMG}
|
|
195
|
+
iconAtlasIMG={iconsAtlasIMG}
|
|
196
|
+
iconAtlasJSON={iconsAtlasJSON}
|
|
197
|
+
entitiesAtlasJSON={entitiesAtlasJSON}
|
|
198
|
+
entitiesAtlasIMG={entitiesAtlasIMG}
|
|
199
|
+
onBack={() => setSelectedMonster(null)}
|
|
200
|
+
/>
|
|
199
201
|
)}
|
|
200
202
|
</>
|
|
201
203
|
);
|
|
@@ -265,11 +265,9 @@ const Value = styled.span`
|
|
|
265
265
|
const StyledCollapsible = styled(Collapsible)`
|
|
266
266
|
background: rgba(255, 255, 255, 0.05);
|
|
267
267
|
border-radius: 4px;
|
|
268
|
-
overflow:
|
|
268
|
+
overflow: auto;
|
|
269
269
|
scrollbar-width: thin;
|
|
270
270
|
scrollbar-color: ${uiColors.darkGray} transparent;
|
|
271
|
-
width: 100%;
|
|
272
|
-
box-sizing: border-box;
|
|
273
271
|
`;
|
|
274
272
|
|
|
275
273
|
const StatGrid = styled.div`
|
|
@@ -356,49 +354,27 @@ const Separator = styled.span`
|
|
|
356
354
|
`;
|
|
357
355
|
|
|
358
356
|
const LootSearchContainer = styled.div`
|
|
359
|
-
padding:
|
|
360
|
-
background: rgba(0, 0, 0, 0.2);
|
|
361
|
-
border-radius: 4px;
|
|
362
|
-
margin: 8px 8px 4px;
|
|
363
|
-
box-sizing: border-box;
|
|
357
|
+
padding: 12px 12px 0;
|
|
364
358
|
`;
|
|
365
359
|
|
|
366
360
|
const StyledSearchBar = styled(SearchBar)`
|
|
367
361
|
width: 100%;
|
|
368
|
-
box-sizing: border-box;
|
|
369
|
-
input {
|
|
370
|
-
background: rgba(0, 0, 0, 0.2) !important;
|
|
371
|
-
border: 1px solid rgba(255, 255, 255, 0.1) !important;
|
|
372
|
-
box-sizing: border-box;
|
|
373
|
-
&:focus {
|
|
374
|
-
border-color: ${uiColors.yellow} !important;
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
362
|
`;
|
|
378
363
|
|
|
379
364
|
const LootGrid = styled.div`
|
|
380
365
|
display: grid;
|
|
381
|
-
grid-template-columns: repeat(auto-
|
|
382
|
-
gap:
|
|
383
|
-
padding:
|
|
384
|
-
width: 100%;
|
|
385
|
-
max-width: 100%;
|
|
386
|
-
box-sizing: border-box;
|
|
387
|
-
|
|
388
|
-
@media (max-width: 768px) {
|
|
389
|
-
grid-template-columns: 1fr;
|
|
390
|
-
padding: 4px;
|
|
391
|
-
}
|
|
366
|
+
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
|
367
|
+
gap: 8px;
|
|
368
|
+
padding: 12px;
|
|
392
369
|
`;
|
|
393
370
|
|
|
394
371
|
const LootItem = styled.div`
|
|
395
372
|
display: flex;
|
|
396
373
|
align-items: center;
|
|
397
|
-
gap:
|
|
374
|
+
gap: 8px;
|
|
398
375
|
background: rgba(255, 255, 255, 0.05);
|
|
399
|
-
padding:
|
|
376
|
+
padding: 8px;
|
|
400
377
|
border-radius: 4px;
|
|
401
|
-
min-width: 0;
|
|
402
378
|
`;
|
|
403
379
|
|
|
404
380
|
const LootDetails = styled.div`
|
|
@@ -2,13 +2,11 @@ import {
|
|
|
2
2
|
IInformationCenterItem,
|
|
3
3
|
IInformationCenterNPC,
|
|
4
4
|
ItemType,
|
|
5
|
-
isMobileOrTablet,
|
|
6
5
|
} from '@rpg-engine/shared';
|
|
7
6
|
import React, { useState } from 'react';
|
|
8
7
|
import styled from 'styled-components';
|
|
9
8
|
import { IOptionsProps } from '../../../Dropdown';
|
|
10
9
|
import { PaginatedContent } from '../../../shared/PaginatedContent/PaginatedContent';
|
|
11
|
-
import { Portal } from '../../../shared/Portal/Portal';
|
|
12
10
|
import { InformationCenterCell } from '../../InformationCenterCell';
|
|
13
11
|
import { InformationCenterItemDetails } from './InformationCenterItemDetails';
|
|
14
12
|
import { InformationCenterItemTooltip } from './InformationCenterItemTooltip';
|
|
@@ -49,7 +47,6 @@ export const InformationCenterItemsSection: React.FC<IItemsSectionProps> = ({
|
|
|
49
47
|
initialSearchQuery,
|
|
50
48
|
tabId,
|
|
51
49
|
}) => {
|
|
52
|
-
const isMobile = isMobileOrTablet();
|
|
53
50
|
const [searchQuery, setSearchQuery] = useState(initialSearchQuery);
|
|
54
51
|
const [selectedItemCategory, setSelectedItemCategory] = useState<string>(
|
|
55
52
|
'all'
|
|
@@ -93,17 +90,15 @@ export const InformationCenterItemsSection: React.FC<IItemsSectionProps> = ({
|
|
|
93
90
|
e: React.MouseEvent,
|
|
94
91
|
item: IInformationCenterItem
|
|
95
92
|
) => {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
setHoveredItem(item);
|
|
102
|
-
}
|
|
93
|
+
setTooltipPosition({
|
|
94
|
+
x: e.clientX + TOOLTIP_OFFSET,
|
|
95
|
+
y: e.clientY,
|
|
96
|
+
});
|
|
97
|
+
setHoveredItem(item);
|
|
103
98
|
};
|
|
104
99
|
|
|
105
100
|
const handleMouseMove = (e: React.MouseEvent) => {
|
|
106
|
-
if (
|
|
101
|
+
if (hoveredItem) {
|
|
107
102
|
setTooltipPosition({
|
|
108
103
|
x: e.clientX + TOOLTIP_OFFSET,
|
|
109
104
|
y: e.clientY,
|
|
@@ -112,17 +107,19 @@ export const InformationCenterItemsSection: React.FC<IItemsSectionProps> = ({
|
|
|
112
107
|
};
|
|
113
108
|
|
|
114
109
|
const handleMouseLeave = () => {
|
|
115
|
-
|
|
116
|
-
setHoveredItem(null);
|
|
117
|
-
}
|
|
110
|
+
setHoveredItem(null);
|
|
118
111
|
};
|
|
119
112
|
|
|
120
113
|
const handleTouchStart = (
|
|
121
114
|
e: React.TouchEvent,
|
|
122
115
|
item: IInformationCenterItem
|
|
123
116
|
) => {
|
|
124
|
-
e.
|
|
125
|
-
|
|
117
|
+
const touch = e.touches[0];
|
|
118
|
+
setTooltipPosition({
|
|
119
|
+
x: touch.clientX + TOOLTIP_OFFSET,
|
|
120
|
+
y: touch.clientY,
|
|
121
|
+
});
|
|
122
|
+
setHoveredItem(item);
|
|
126
123
|
};
|
|
127
124
|
|
|
128
125
|
const handleItemClick = (item: IInformationCenterItem) => {
|
|
@@ -173,7 +170,7 @@ export const InformationCenterItemsSection: React.FC<IItemsSectionProps> = ({
|
|
|
173
170
|
layout="grid"
|
|
174
171
|
itemHeight="180px"
|
|
175
172
|
/>
|
|
176
|
-
{
|
|
173
|
+
{hoveredItem && (
|
|
177
174
|
<TooltipWrapper
|
|
178
175
|
style={{ top: tooltipPosition.y, left: tooltipPosition.x }}
|
|
179
176
|
>
|
|
@@ -181,15 +178,13 @@ export const InformationCenterItemsSection: React.FC<IItemsSectionProps> = ({
|
|
|
181
178
|
</TooltipWrapper>
|
|
182
179
|
)}
|
|
183
180
|
{selectedItem && (
|
|
184
|
-
<
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
/>
|
|
192
|
-
</Portal>
|
|
181
|
+
<InformationCenterItemDetails
|
|
182
|
+
item={selectedItem}
|
|
183
|
+
itemsAtlasJSON={itemsAtlasJSON}
|
|
184
|
+
itemsAtlasIMG={itemsAtlasIMG}
|
|
185
|
+
droppedBy={getDroppedByNPCs(selectedItem.key, bestiaryItems)}
|
|
186
|
+
onBack={() => setSelectedItem(null)}
|
|
187
|
+
/>
|
|
193
188
|
)}
|
|
194
189
|
</>
|
|
195
190
|
);
|
|
@@ -49,45 +49,32 @@ export const BaseInformationDetails: React.FC<IBaseInformationDetailsProps> = ({
|
|
|
49
49
|
};
|
|
50
50
|
|
|
51
51
|
const Container = styled.div`
|
|
52
|
-
position:
|
|
52
|
+
position: absolute;
|
|
53
53
|
inset: 0;
|
|
54
54
|
display: flex;
|
|
55
55
|
justify-content: center;
|
|
56
56
|
align-items: center;
|
|
57
|
-
z-index:
|
|
57
|
+
z-index: 1000;
|
|
58
58
|
`;
|
|
59
59
|
|
|
60
60
|
const Overlay = styled.div`
|
|
61
|
-
position:
|
|
61
|
+
position: absolute;
|
|
62
62
|
inset: 0;
|
|
63
63
|
background-color: rgba(0, 0, 0, 0.8);
|
|
64
64
|
`;
|
|
65
65
|
|
|
66
66
|
const Modal = styled.div`
|
|
67
|
-
position:
|
|
67
|
+
position: relative;
|
|
68
|
+
width: 90%;
|
|
69
|
+
height: 90%;
|
|
68
70
|
background-color: rgba(0, 0, 0, 0.95);
|
|
69
71
|
border-radius: 4px;
|
|
70
|
-
padding:
|
|
71
|
-
overflow:
|
|
72
|
+
padding: 16px;
|
|
73
|
+
overflow-y: auto;
|
|
72
74
|
z-index: 1;
|
|
73
75
|
font-family: 'Press Start 2P', cursive;
|
|
74
76
|
border: 1px solid ${uiColors.darkGray};
|
|
75
77
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
|
76
|
-
width: 90%;
|
|
77
|
-
height: 90%;
|
|
78
|
-
top: 5%;
|
|
79
|
-
left: 5%;
|
|
80
|
-
max-width: 800px;
|
|
81
|
-
margin: 0 auto;
|
|
82
|
-
|
|
83
|
-
@media (max-width: 768px) {
|
|
84
|
-
width: 100%;
|
|
85
|
-
height: 100%;
|
|
86
|
-
top: 0;
|
|
87
|
-
left: 0;
|
|
88
|
-
border-radius: 0;
|
|
89
|
-
padding: 8px;
|
|
90
|
-
}
|
|
91
78
|
|
|
92
79
|
&::-webkit-scrollbar {
|
|
93
80
|
width: 2px;
|
|
@@ -139,19 +126,9 @@ const Header = styled.div`
|
|
|
139
126
|
const Content = styled.div`
|
|
140
127
|
display: flex;
|
|
141
128
|
flex-direction: column;
|
|
142
|
-
gap:
|
|
143
|
-
height:
|
|
144
|
-
overflow
|
|
145
|
-
overflow-x: hidden;
|
|
146
|
-
padding-right: 6px;
|
|
147
|
-
margin-right: -6px;
|
|
148
|
-
|
|
149
|
-
@media (max-width: 768px) {
|
|
150
|
-
height: calc(100% - 64px);
|
|
151
|
-
gap: 8px;
|
|
152
|
-
padding-right: 4px;
|
|
153
|
-
margin-right: -4px;
|
|
154
|
-
}
|
|
129
|
+
gap: 16px;
|
|
130
|
+
height: 100%;
|
|
131
|
+
overflow: auto;
|
|
155
132
|
`;
|
|
156
133
|
|
|
157
134
|
const Title = styled.h2`
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IItem } from '@rpg-engine/shared';
|
|
1
|
+
import { IItem, ItemQualityLevel } from '@rpg-engine/shared';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import styled from 'styled-components';
|
|
4
4
|
import { uiColors } from '../../../constants/uiColors';
|
|
@@ -6,6 +6,7 @@ import { uiFonts } from '../../../constants/uiFonts';
|
|
|
6
6
|
import { SpriteFromAtlas } from '../../shared/SpriteFromAtlas';
|
|
7
7
|
import { ErrorBoundary } from '../Inventory/ErrorBoundary';
|
|
8
8
|
import { EquipmentSlotSpriteByType } from '../Inventory/ItemSlot';
|
|
9
|
+
import { qualityColorHex } from '../Inventory/ItemSlotQuality';
|
|
9
10
|
import { rarityColor } from '../Inventory/ItemSlotRarity';
|
|
10
11
|
|
|
11
12
|
interface IItemInfoProps {
|
|
@@ -191,8 +192,24 @@ const Container = styled.div<{ item: IItem }>`
|
|
|
191
192
|
padding: 0.5rem;
|
|
192
193
|
font-size: ${uiFonts.size.small};
|
|
193
194
|
border: 3px solid ${({ item }) => rarityColor(item) ?? uiColors.lightGray};
|
|
195
|
+
box-shadow: ${({ item }) => `0 0 5px 2px ${rarityColor(item)}`};
|
|
194
196
|
height: max-content;
|
|
195
197
|
width: 18rem;
|
|
198
|
+
position: relative;
|
|
199
|
+
|
|
200
|
+
${({ item }) =>
|
|
201
|
+
item?.quality && item.quality !== ItemQualityLevel.Normal &&
|
|
202
|
+
`
|
|
203
|
+
&::before {
|
|
204
|
+
content: '★';
|
|
205
|
+
position: absolute;
|
|
206
|
+
top: 0.2rem;
|
|
207
|
+
left: 0.5rem;
|
|
208
|
+
font-size: 1.2rem;
|
|
209
|
+
color: ${qualityColorHex(item)};
|
|
210
|
+
text-shadow: 0 0 3px black;
|
|
211
|
+
}
|
|
212
|
+
`}
|
|
196
213
|
|
|
197
214
|
@media (max-width: 640px) {
|
|
198
215
|
width: 80vw;
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
ItemContainerType,
|
|
7
7
|
ItemSlotType,
|
|
8
8
|
ItemSubType,
|
|
9
|
-
ItemType
|
|
9
|
+
ItemType
|
|
10
10
|
} from '@rpg-engine/shared';
|
|
11
11
|
|
|
12
12
|
import { observer } from 'mobx-react-lite';
|
|
@@ -15,10 +15,11 @@ import Draggable, { DraggableEventHandler } from 'react-draggable';
|
|
|
15
15
|
import styled from 'styled-components';
|
|
16
16
|
import useTouchTarget from '../../../hooks/useTouchTarget';
|
|
17
17
|
import { IPosition } from '../../../types/eventTypes';
|
|
18
|
-
import { rarityColor } from './ItemSlotRarity';
|
|
19
|
-
import { ItemSlotRenderer } from './ItemSlotRenderer';
|
|
20
18
|
import { useItemSlotDetails } from './context/ItemSlotDetailsContext';
|
|
21
19
|
import { useItemSlotDragging } from './context/ItemSlotDraggingContext';
|
|
20
|
+
import { qualityColorHex } from './ItemSlotQuality';
|
|
21
|
+
import { rarityColor } from './ItemSlotRarity';
|
|
22
|
+
import { ItemSlotRenderer } from './ItemSlotRenderer';
|
|
22
23
|
|
|
23
24
|
export const EquipmentSlotSpriteByType: any = {
|
|
24
25
|
Neck: 'accessories/corruption-necklace.png',
|
|
@@ -539,6 +540,17 @@ const Container = styled.div<ContainerTypes>`
|
|
|
539
540
|
${({ item }) => `0 0 4px 3px ${rarityColor(item)}`};
|
|
540
541
|
}
|
|
541
542
|
|
|
543
|
+
.quality-star {
|
|
544
|
+
position: absolute;
|
|
545
|
+
top: 0.5rem;
|
|
546
|
+
left: 0.5rem;
|
|
547
|
+
font-size: 1.2rem;
|
|
548
|
+
z-index: 2;
|
|
549
|
+
text-shadow: 0 0 3px black;
|
|
550
|
+
pointer-events: none;
|
|
551
|
+
color: ${({ item }) => qualityColorHex(item)};
|
|
552
|
+
}
|
|
553
|
+
|
|
542
554
|
&::before {
|
|
543
555
|
content: '';
|
|
544
556
|
position: absolute;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { IItem, ItemQualityLevel } from '@rpg-engine/shared';
|
|
2
|
+
|
|
3
|
+
export const qualityColorHex = (item: IItem | null) => {
|
|
4
|
+
switch (item?.quality) {
|
|
5
|
+
case ItemQualityLevel.HighQuality:
|
|
6
|
+
return '#00bfff';
|
|
7
|
+
case ItemQualityLevel.Exceptional:
|
|
8
|
+
return '#ff8c00';
|
|
9
|
+
case ItemQualityLevel.Mastercrafted:
|
|
10
|
+
return '#ff00ff';
|
|
11
|
+
case ItemQualityLevel.Ancient:
|
|
12
|
+
return '#ffd700';
|
|
13
|
+
case ItemQualityLevel.Mythic:
|
|
14
|
+
return '#ff0080';
|
|
15
|
+
default:
|
|
16
|
+
return 'transparent';
|
|
17
|
+
}
|
|
18
|
+
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
|
+
getItemTextureKeyPath,
|
|
2
3
|
IItem,
|
|
3
4
|
ItemContainerType,
|
|
5
|
+
ItemQualityLevel,
|
|
4
6
|
ItemSlotType,
|
|
5
|
-
getItemTextureKeyPath,
|
|
6
7
|
} from '@rpg-engine/shared';
|
|
7
8
|
import React from 'react';
|
|
8
9
|
import { v4 as uuidv4 } from 'uuid';
|
|
@@ -46,6 +47,9 @@ export const ItemSlotRenderer: React.FC<IProps> = ({
|
|
|
46
47
|
|
|
47
48
|
return (
|
|
48
49
|
<ErrorBoundary key={item._id}>
|
|
50
|
+
{item.quality && item.quality !== ItemQualityLevel.Normal && (
|
|
51
|
+
<div className="quality-star">★</div>
|
|
52
|
+
)}
|
|
49
53
|
<SpriteFromAtlas
|
|
50
54
|
atlasIMG={atlasIMG}
|
|
51
55
|
atlasJSON={atlasJSON}
|
|
@@ -101,5 +105,5 @@ export const ItemSlotRenderer: React.FC<IProps> = ({
|
|
|
101
105
|
}
|
|
102
106
|
};
|
|
103
107
|
|
|
104
|
-
return
|
|
108
|
+
return onRenderSlot(item);
|
|
105
109
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
IItem,
|
|
3
3
|
IItemContainer,
|
|
4
|
+
ItemQualityLevel,
|
|
4
5
|
ItemRarities,
|
|
5
6
|
ItemSlotType,
|
|
6
7
|
ItemSubType,
|
|
@@ -81,6 +82,7 @@ export const items: IItem[] = [
|
|
|
81
82
|
createdAt: '2022-06-04T03:18:09.335Z',
|
|
82
83
|
updatedAt: '2022-06-04T18:16:49.056Z',
|
|
83
84
|
rarity: ItemRarities.Legendary,
|
|
85
|
+
quality: ItemQualityLevel.Mythic,
|
|
84
86
|
canBePurchasedOnlyByPremiumPlans: [
|
|
85
87
|
UserAccountTypes.PremiumGold,
|
|
86
88
|
UserAccountTypes.PremiumUltimate,
|
|
@@ -167,6 +169,7 @@ export const items: IItem[] = [
|
|
|
167
169
|
createdAt: '2022-06-04T03:18:09.335Z',
|
|
168
170
|
updatedAt: '2022-06-04T18:16:49.056Z',
|
|
169
171
|
rarity: ItemRarities.Epic,
|
|
172
|
+
quality: ItemQualityLevel.Normal,
|
|
170
173
|
attachedGems: [
|
|
171
174
|
{
|
|
172
175
|
gemEntityEffectsAdd: ['poison'],
|
|
@@ -221,6 +224,7 @@ export const items: IItem[] = [
|
|
|
221
224
|
createdAt: '2022-06-04T03:18:09.335Z',
|
|
222
225
|
updatedAt: '2022-06-04T18:16:49.056Z',
|
|
223
226
|
rarity: ItemRarities.Uncommon,
|
|
227
|
+
quality: ItemQualityLevel.HighQuality,
|
|
224
228
|
},
|
|
225
229
|
{
|
|
226
230
|
_id: '629acek4j7c8e8002ff60034',
|
|
@@ -255,6 +259,7 @@ export const items: IItem[] = [
|
|
|
255
259
|
createdAt: '2022-06-04T03:18:09.335Z',
|
|
256
260
|
updatedAt: '2022-06-04T18:16:49.056Z',
|
|
257
261
|
rarity: ItemRarities.Rare,
|
|
262
|
+
quality: ItemQualityLevel.Ancient,
|
|
258
263
|
},
|
|
259
264
|
{
|
|
260
265
|
_id: '629acek4j7c8e8002fg60034',
|
|
@@ -289,6 +294,7 @@ export const items: IItem[] = [
|
|
|
289
294
|
createdAt: '2022-06-04T03:18:09.335Z',
|
|
290
295
|
updatedAt: '2022-06-04T18:16:49.056Z',
|
|
291
296
|
rarity: ItemRarities.Common,
|
|
297
|
+
quality: ItemQualityLevel.Mastercrafted,
|
|
292
298
|
},
|
|
293
299
|
{
|
|
294
300
|
_id: '392acek4j7c8e8002ff60403',
|
|
@@ -323,6 +329,7 @@ export const items: IItem[] = [
|
|
|
323
329
|
createdAt: '2022-06-04T03:18:09.335Z',
|
|
324
330
|
updatedAt: '2022-06-04T18:16:49.056Z',
|
|
325
331
|
rarity: ItemRarities.Common,
|
|
332
|
+
quality: ItemQualityLevel.Exceptional,
|
|
326
333
|
},
|
|
327
334
|
createBagItem('392acek4j7c8e8002ff60404', '#FF0000'), // red
|
|
328
335
|
createBagItem('392acek4j7c8e8002ff60405', '#0000FF'), // blue
|