@rpg-engine/long-bow 0.8.35 → 0.8.37
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 +376 -220
- 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 +377 -221
- package/dist/long-bow.esm.js.map +1 -1
- package/package.json +2 -2
- package/src/components/InformationCenter/InformationCenter.tsx +20 -2
- package/src/components/InformationCenter/InformationCenterCell.tsx +109 -11
- package/src/components/InformationCenter/sections/bestiary/InformationCenterBestiarySection.tsx +1 -1
- package/src/components/InformationCenter/sections/items/InformationCenterItemsSection.tsx +1 -1
- package/src/components/InformationCenter/sections/tutorials/InformationCenterTutorialsSection.tsx +5 -3
- package/src/components/InternalTabs/InternalTabs.tsx +19 -3
- 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/AdvancedFilters/AdvancedFilters.tsx +160 -33
- package/src/components/shared/PaginatedContent/PaginatedContent.tsx +67 -10
- package/src/hooks/useTooltipPosition.ts +24 -5
- 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.37",
|
|
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",
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
IInformationCenterItem,
|
|
7
7
|
IInformationCenterNPC,
|
|
8
8
|
IVideoGuide,
|
|
9
|
+
isMobileOrTablet,
|
|
9
10
|
} from '@rpg-engine/shared';
|
|
10
11
|
import { DraggableContainer } from '../DraggableContainer';
|
|
11
12
|
import { InternalTabs } from '../InternalTabs/InternalTabs';
|
|
@@ -45,6 +46,7 @@ export const InformationCenter: React.FC<IInformationCenterProps> = ({
|
|
|
45
46
|
initialSearchQuery = '',
|
|
46
47
|
}) => {
|
|
47
48
|
const [activeTab, setActiveTab] = useState('bestiary');
|
|
49
|
+
const isMobile = isMobileOrTablet();
|
|
48
50
|
|
|
49
51
|
if (loading) {
|
|
50
52
|
return <LoadingMessage>Loading...</LoadingMessage>;
|
|
@@ -103,6 +105,8 @@ export const InformationCenter: React.FC<IInformationCenterProps> = ({
|
|
|
103
105
|
<DraggableContainer
|
|
104
106
|
title="Information Center"
|
|
105
107
|
type={RPGUIContainerTypes.Framed}
|
|
108
|
+
width={isMobile ? '95%' : '80%'}
|
|
109
|
+
minWidth="300px"
|
|
106
110
|
>
|
|
107
111
|
<Container>
|
|
108
112
|
<InternalTabs
|
|
@@ -122,9 +126,23 @@ export const InformationCenter: React.FC<IInformationCenterProps> = ({
|
|
|
122
126
|
|
|
123
127
|
const Container = styled.div`
|
|
124
128
|
width: 100%;
|
|
125
|
-
max-width:
|
|
129
|
+
max-width: 100%;
|
|
126
130
|
margin: 0 auto;
|
|
127
|
-
padding:
|
|
131
|
+
padding: 0.125rem;
|
|
132
|
+
overflow: hidden;
|
|
133
|
+
box-sizing: border-box;
|
|
134
|
+
|
|
135
|
+
@media (min-width: 320px) {
|
|
136
|
+
padding: 0.25rem;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
@media (min-width: 360px) {
|
|
140
|
+
padding: 0.5rem;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
@media (min-width: 480px) {
|
|
144
|
+
padding: 0.75rem;
|
|
145
|
+
}
|
|
128
146
|
`;
|
|
129
147
|
|
|
130
148
|
const LoadingMessage = styled.div`
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
2
|
import styled from 'styled-components';
|
|
3
|
+
import { UI_BREAKPOINT_MOBILE } from '../../constants/uiBreakpoints';
|
|
3
4
|
import { SpriteFromAtlas } from '../shared/SpriteFromAtlas';
|
|
4
5
|
|
|
5
6
|
interface IInformationCenterCellProps {
|
|
@@ -25,13 +26,46 @@ export const InformationCenterCell: React.FC<IInformationCenterCellProps> = ({
|
|
|
25
26
|
onMouseMove,
|
|
26
27
|
onTouchStart,
|
|
27
28
|
}) => {
|
|
29
|
+
const [touchStartY, setTouchStartY] = useState<number | null>(null);
|
|
30
|
+
const [touchStartX, setTouchStartX] = useState<number | null>(null);
|
|
31
|
+
const [isTouchScrolling, setIsTouchScrolling] = useState(false);
|
|
32
|
+
|
|
33
|
+
const handleTouchStart = (e: React.TouchEvent) => {
|
|
34
|
+
setTouchStartY(e.touches[0].clientY);
|
|
35
|
+
setTouchStartX(e.touches[0].clientX);
|
|
36
|
+
setIsTouchScrolling(false);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const handleTouchMove = (e: React.TouchEvent) => {
|
|
40
|
+
if (touchStartY !== null && touchStartX !== null) {
|
|
41
|
+
const touchDiffY = Math.abs(e.touches[0].clientY - touchStartY);
|
|
42
|
+
const touchDiffX = Math.abs(e.touches[0].clientX - touchStartX);
|
|
43
|
+
|
|
44
|
+
// If user moved finger more than 15px in any direction, consider it scrolling
|
|
45
|
+
if (touchDiffY > 15 || touchDiffX > 15) {
|
|
46
|
+
setIsTouchScrolling(true);
|
|
47
|
+
e.stopPropagation(); // Prevent parent elements from handling this touch
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const handleTouchEnd = (e: React.TouchEvent) => {
|
|
53
|
+
if (!isTouchScrolling && onTouchStart) {
|
|
54
|
+
onTouchStart(e);
|
|
55
|
+
}
|
|
56
|
+
setTouchStartY(null);
|
|
57
|
+
setTouchStartX(null);
|
|
58
|
+
};
|
|
59
|
+
|
|
28
60
|
return (
|
|
29
61
|
<CellContainer
|
|
30
62
|
onClick={onClick}
|
|
31
63
|
onMouseEnter={onMouseEnter}
|
|
32
64
|
onMouseLeave={onMouseLeave}
|
|
33
65
|
onMouseMove={onMouseMove}
|
|
34
|
-
onTouchStart={
|
|
66
|
+
onTouchStart={handleTouchStart}
|
|
67
|
+
onTouchMove={handleTouchMove}
|
|
68
|
+
onTouchEnd={handleTouchEnd}
|
|
35
69
|
>
|
|
36
70
|
<SpriteContainer>
|
|
37
71
|
<SpriteFromAtlas
|
|
@@ -43,7 +77,9 @@ export const InformationCenterCell: React.FC<IInformationCenterCellProps> = ({
|
|
|
43
77
|
imgScale={1}
|
|
44
78
|
/>
|
|
45
79
|
</SpriteContainer>
|
|
46
|
-
<
|
|
80
|
+
<CellNameContainer>
|
|
81
|
+
<CellName>{name}</CellName>
|
|
82
|
+
</CellNameContainer>
|
|
47
83
|
</CellContainer>
|
|
48
84
|
);
|
|
49
85
|
};
|
|
@@ -51,7 +87,7 @@ export const InformationCenterCell: React.FC<IInformationCenterCellProps> = ({
|
|
|
51
87
|
const CellContainer = styled.div`
|
|
52
88
|
position: relative;
|
|
53
89
|
background: rgba(0, 0, 0, 0.2);
|
|
54
|
-
padding: 0.
|
|
90
|
+
padding: 0.2rem;
|
|
55
91
|
border-radius: 4px;
|
|
56
92
|
display: flex;
|
|
57
93
|
flex-direction: column;
|
|
@@ -61,9 +97,22 @@ const CellContainer = styled.div`
|
|
|
61
97
|
transition: background-color 0.2s ease;
|
|
62
98
|
width: 100%;
|
|
63
99
|
height: 100%;
|
|
64
|
-
min-
|
|
65
|
-
min-height: 120px;
|
|
100
|
+
min-height: 90px;
|
|
66
101
|
box-sizing: border-box;
|
|
102
|
+
gap: 0.2rem;
|
|
103
|
+
margin: 0;
|
|
104
|
+
|
|
105
|
+
@media (min-width: 360px) {
|
|
106
|
+
padding: 0.3rem;
|
|
107
|
+
gap: 0.3rem;
|
|
108
|
+
margin: 1px;
|
|
109
|
+
width: calc(100% - 2px);
|
|
110
|
+
min-height: 100px;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
@media (min-width: ${UI_BREAKPOINT_MOBILE}) {
|
|
114
|
+
min-height: 110px;
|
|
115
|
+
}
|
|
67
116
|
|
|
68
117
|
&:hover {
|
|
69
118
|
background: rgba(0, 0, 0, 0.3);
|
|
@@ -71,16 +120,34 @@ const CellContainer = styled.div`
|
|
|
71
120
|
`;
|
|
72
121
|
|
|
73
122
|
const SpriteContainer = styled.div`
|
|
74
|
-
margin-bottom: 0.5rem;
|
|
75
123
|
display: flex;
|
|
76
124
|
justify-content: center;
|
|
77
125
|
align-items: center;
|
|
78
|
-
width:
|
|
79
|
-
height:
|
|
126
|
+
width: 32px;
|
|
127
|
+
height: 32px;
|
|
80
128
|
position: relative;
|
|
81
129
|
background: rgba(0, 0, 0, 0.3);
|
|
82
130
|
border-radius: 4px;
|
|
83
131
|
flex-shrink: 0;
|
|
132
|
+
overflow: hidden;
|
|
133
|
+
|
|
134
|
+
padding: 1rem;
|
|
135
|
+
margin-top: 1rem;
|
|
136
|
+
|
|
137
|
+
@media (min-width: 360px) {
|
|
138
|
+
width: 36px;
|
|
139
|
+
height: 36px;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
@media (min-width: 480px) {
|
|
143
|
+
width: 42px;
|
|
144
|
+
height: 42px;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
@media (min-width: ${UI_BREAKPOINT_MOBILE}) {
|
|
148
|
+
width: 48px;
|
|
149
|
+
height: 48px;
|
|
150
|
+
}
|
|
84
151
|
|
|
85
152
|
.sprite-from-atlas-img {
|
|
86
153
|
position: absolute;
|
|
@@ -91,13 +158,44 @@ const SpriteContainer = styled.div`
|
|
|
91
158
|
}
|
|
92
159
|
`;
|
|
93
160
|
|
|
161
|
+
const CellNameContainer = styled.div`
|
|
162
|
+
display: flex;
|
|
163
|
+
flex-direction: column;
|
|
164
|
+
align-items: center;
|
|
165
|
+
justify-content: center;
|
|
166
|
+
flex: 1;
|
|
167
|
+
width: 100%;
|
|
168
|
+
padding-top: 0.1rem;
|
|
169
|
+
`;
|
|
170
|
+
|
|
94
171
|
const CellName = styled.h3`
|
|
95
|
-
font-size: 0.
|
|
172
|
+
font-size: 0.5rem;
|
|
96
173
|
color: #fef08a;
|
|
97
174
|
margin: 0;
|
|
98
175
|
text-align: center;
|
|
99
176
|
font-family: 'Press Start 2P', cursive;
|
|
100
|
-
line-height: 1.
|
|
177
|
+
line-height: 1.1;
|
|
101
178
|
word-break: break-word;
|
|
102
179
|
max-width: 100%;
|
|
180
|
+
overflow-wrap: break-word;
|
|
181
|
+
hyphens: auto;
|
|
182
|
+
width: 100%;
|
|
183
|
+
padding: 0 0.125rem;
|
|
184
|
+
box-sizing: border-box;
|
|
185
|
+
|
|
186
|
+
@media (min-width: 320px) {
|
|
187
|
+
padding: 0 0.25rem;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
@media (min-width: 360px) {
|
|
191
|
+
font-size: 0.55rem;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
@media (min-width: 480px) {
|
|
195
|
+
font-size: 0.6rem;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
@media (min-width: ${UI_BREAKPOINT_MOBILE}) {
|
|
199
|
+
font-size: 0.65rem;
|
|
200
|
+
}
|
|
103
201
|
`;
|
|
@@ -153,7 +153,7 @@ export const InformationCenterItemsSection: React.FC<IItemsSectionProps> = ({
|
|
|
153
153
|
dependencies={[selectedItemCategory, selectedTier]}
|
|
154
154
|
tabId={tabId}
|
|
155
155
|
layout="grid"
|
|
156
|
-
itemHeight=
|
|
156
|
+
itemHeight={isMobile ? '150px' : '180px'}
|
|
157
157
|
/>
|
|
158
158
|
{!isMobile && tooltipState && tooltipState.item && (
|
|
159
159
|
<Portal>
|
package/src/components/InformationCenter/sections/tutorials/InformationCenterTutorialsSection.tsx
CHANGED
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
IVideoGuide,
|
|
3
3
|
VideoGuideCategory,
|
|
4
4
|
VideoGuideLanguage,
|
|
5
|
+
isMobileOrTablet,
|
|
5
6
|
} from '@rpg-engine/shared';
|
|
6
7
|
import React, { useMemo, useState } from 'react';
|
|
7
8
|
import styled from 'styled-components';
|
|
@@ -26,6 +27,7 @@ export const InformationCenterTutorialsSection: React.FC<ITutorialsSectionProps>
|
|
|
26
27
|
initialSearchQuery,
|
|
27
28
|
tabId,
|
|
28
29
|
}) => {
|
|
30
|
+
const isMobile = isMobileOrTablet();
|
|
29
31
|
const [searchQuery, setSearchQuery] = useState(initialSearchQuery);
|
|
30
32
|
const [selectedCategory, setSelectedCategory] = useState<string>('all');
|
|
31
33
|
const [, setCurrentPage] = useState(1);
|
|
@@ -81,7 +83,7 @@ export const InformationCenterTutorialsSection: React.FC<ITutorialsSectionProps>
|
|
|
81
83
|
</Ellipsis>
|
|
82
84
|
</GuideTitle>
|
|
83
85
|
<GuideDescription>
|
|
84
|
-
<Ellipsis maxWidth="100%" maxLines={5}>
|
|
86
|
+
<Ellipsis maxWidth="100%" maxLines={isMobile ? 3 : 5}>
|
|
85
87
|
{guide.description}
|
|
86
88
|
</Ellipsis>
|
|
87
89
|
</GuideDescription>
|
|
@@ -145,9 +147,9 @@ export const InformationCenterTutorialsSection: React.FC<ITutorialsSectionProps>
|
|
|
145
147
|
dependencies={[selectedCategory]}
|
|
146
148
|
tabId={tabId}
|
|
147
149
|
layout="grid"
|
|
148
|
-
gridColumns={GRID_COLUMNS}
|
|
150
|
+
gridColumns={isMobile ? 1 : GRID_COLUMNS}
|
|
149
151
|
itemsPerPage={ITEMS_PER_PAGE}
|
|
150
|
-
itemHeight=
|
|
152
|
+
itemHeight={isMobile ? '280px' : '320px'}
|
|
151
153
|
/>
|
|
152
154
|
);
|
|
153
155
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import styled from 'styled-components';
|
|
3
|
+
import { UI_BREAKPOINT_MOBILE } from '../../constants/uiBreakpoints';
|
|
3
4
|
|
|
4
5
|
interface TabItem {
|
|
5
6
|
id: string;
|
|
@@ -73,14 +74,27 @@ const TabButton = styled.button<{
|
|
|
73
74
|
hoverColor: string;
|
|
74
75
|
}>`
|
|
75
76
|
flex: 1;
|
|
76
|
-
padding: 0.5rem
|
|
77
|
-
font-size: 0.
|
|
77
|
+
padding: 0.25rem 0.5rem;
|
|
78
|
+
font-size: 0.75rem;
|
|
78
79
|
font-weight: 500;
|
|
79
80
|
border-right: 1px solid ${props => props.borderColor};
|
|
80
81
|
background-color: ${props =>
|
|
81
82
|
props.active ? props.activeColor : 'transparent'};
|
|
82
83
|
color: ${props =>
|
|
83
84
|
props.active ? props.activeTextColor : props.inactiveColor};
|
|
85
|
+
white-space: nowrap;
|
|
86
|
+
overflow: hidden;
|
|
87
|
+
text-overflow: ellipsis;
|
|
88
|
+
|
|
89
|
+
@media (min-width: 480px) {
|
|
90
|
+
padding: 0.375rem 0.75rem;
|
|
91
|
+
font-size: 0.8125rem;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
@media (min-width: ${UI_BREAKPOINT_MOBILE}) {
|
|
95
|
+
padding: 0.5rem 1rem;
|
|
96
|
+
font-size: 0.875rem;
|
|
97
|
+
}
|
|
84
98
|
|
|
85
99
|
&:last-child {
|
|
86
100
|
border-right: none;
|
|
@@ -92,4 +106,6 @@ const TabButton = styled.button<{
|
|
|
92
106
|
}
|
|
93
107
|
`;
|
|
94
108
|
|
|
95
|
-
const ContentWrapper = styled.div
|
|
109
|
+
const ContentWrapper = styled.div`
|
|
110
|
+
width: 100%;
|
|
111
|
+
`;
|
|
@@ -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
|
};
|