@rpg-engine/long-bow 0.8.205 → 0.8.207
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/Marketplace/CharacterListingModal.d.ts +2 -0
- package/dist/components/Marketplace/MyCharacterListingsPanel.d.ts +2 -0
- package/dist/long-bow.cjs.development.js +66 -37
- 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 +66 -37
- package/dist/long-bow.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Marketplace/CharacterListingModal.tsx +44 -23
- package/src/components/Marketplace/Marketplace.tsx +1 -0
- package/src/components/Marketplace/MyCharacterListingsPanel.tsx +4 -0
package/package.json
CHANGED
|
@@ -15,6 +15,8 @@ export interface ICharacterListingModalProps {
|
|
|
15
15
|
isOpen: boolean;
|
|
16
16
|
onClose: () => void;
|
|
17
17
|
accountCharacters: ICharacter[];
|
|
18
|
+
/** ID of the currently active/playing character — cannot be listed */
|
|
19
|
+
activeCharacterId?: string;
|
|
18
20
|
/** Items atlas — for UI sprites like the DC coin */
|
|
19
21
|
atlasJSON: any;
|
|
20
22
|
atlasIMG: any;
|
|
@@ -30,6 +32,7 @@ export const CharacterListingModal: React.FC<ICharacterListingModalProps> = ({
|
|
|
30
32
|
isOpen,
|
|
31
33
|
onClose,
|
|
32
34
|
accountCharacters,
|
|
35
|
+
activeCharacterId,
|
|
33
36
|
atlasJSON,
|
|
34
37
|
atlasIMG,
|
|
35
38
|
characterAtlasJSON,
|
|
@@ -42,13 +45,22 @@ export const CharacterListingModal: React.FC<ICharacterListingModalProps> = ({
|
|
|
42
45
|
const [price, setPrice] = useState('');
|
|
43
46
|
const [isConfirming, setIsConfirming] = useState(false);
|
|
44
47
|
|
|
48
|
+
const stopPropagation = useCallback(
|
|
49
|
+
(e: React.MouseEvent | React.TouchEvent | React.PointerEvent) => {
|
|
50
|
+
e.stopPropagation();
|
|
51
|
+
},
|
|
52
|
+
[]
|
|
53
|
+
);
|
|
54
|
+
|
|
45
55
|
if (!isOpen) return null;
|
|
46
56
|
|
|
47
57
|
const eligibleCharacters = accountCharacters.filter(
|
|
48
58
|
c => !c.isListedForSale && !c.tradedAt
|
|
49
59
|
);
|
|
50
60
|
|
|
51
|
-
const
|
|
61
|
+
const isActiveCharacter = (c: ICharacter) => !!activeCharacterId && c._id === activeCharacterId;
|
|
62
|
+
|
|
63
|
+
const canList = !!selectedId && Number(price) > 0 && selectedId !== activeCharacterId;
|
|
52
64
|
|
|
53
65
|
const handleClose = () => {
|
|
54
66
|
setSelectedId(null);
|
|
@@ -71,13 +83,6 @@ export const CharacterListingModal: React.FC<ICharacterListingModalProps> = ({
|
|
|
71
83
|
onClose();
|
|
72
84
|
};
|
|
73
85
|
|
|
74
|
-
const stopPropagation = useCallback(
|
|
75
|
-
(e: React.MouseEvent | React.TouchEvent | React.PointerEvent) => {
|
|
76
|
-
e.stopPropagation();
|
|
77
|
-
},
|
|
78
|
-
[]
|
|
79
|
-
);
|
|
80
|
-
|
|
81
86
|
const getLevel = (c: ICharacter) => c.skills?.level || 1;
|
|
82
87
|
|
|
83
88
|
return (
|
|
@@ -110,22 +115,25 @@ export const CharacterListingModal: React.FC<ICharacterListingModalProps> = ({
|
|
|
110
115
|
) : (
|
|
111
116
|
eligibleCharacters.map(character => {
|
|
112
117
|
const isSelected = selectedId === character._id;
|
|
118
|
+
const isActive = isActiveCharacter(character);
|
|
113
119
|
return (
|
|
114
120
|
<CharacterRow
|
|
115
121
|
key={character._id}
|
|
116
|
-
$selected={isSelected}
|
|
117
|
-
|
|
122
|
+
$selected={isSelected && !isActive}
|
|
123
|
+
$disabled={isActive}
|
|
124
|
+
onPointerDown={() => !isActive && setSelectedId(character._id!)}
|
|
118
125
|
role="radio"
|
|
119
|
-
aria-checked={isSelected}
|
|
120
|
-
|
|
126
|
+
aria-checked={isSelected && !isActive}
|
|
127
|
+
aria-disabled={isActive}
|
|
128
|
+
tabIndex={isActive ? -1 : 0}
|
|
121
129
|
onKeyDown={e => {
|
|
122
|
-
if (e.key === 'Enter' || e.key === ' ') {
|
|
130
|
+
if (!isActive && (e.key === 'Enter' || e.key === ' ')) {
|
|
123
131
|
e.preventDefault();
|
|
124
132
|
setSelectedId(character._id!);
|
|
125
133
|
}
|
|
126
134
|
}}
|
|
127
135
|
>
|
|
128
|
-
<RadioCircle $selected={isSelected} />
|
|
136
|
+
<RadioCircle $selected={isSelected && !isActive} $disabled={isActive} />
|
|
129
137
|
<SpriteWrapper>
|
|
130
138
|
<SpriteFromAtlas
|
|
131
139
|
atlasIMG={characterAtlasIMG}
|
|
@@ -140,6 +148,7 @@ export const CharacterListingModal: React.FC<ICharacterListingModalProps> = ({
|
|
|
140
148
|
<CharacterName>{character.name || 'Unknown'}</CharacterName>
|
|
141
149
|
<CharacterMeta>Level {getLevel(character)}</CharacterMeta>
|
|
142
150
|
</CharacterInfo>
|
|
151
|
+
{isActive && <ActiveTag>In-game</ActiveTag>}
|
|
143
152
|
</CharacterRow>
|
|
144
153
|
);
|
|
145
154
|
})
|
|
@@ -266,20 +275,21 @@ const CharacterList = styled.div`
|
|
|
266
275
|
&::-webkit-scrollbar-thumb { background: rgba(245,158,11,0.3); border-radius: 4px; }
|
|
267
276
|
`;
|
|
268
277
|
|
|
269
|
-
const CharacterRow = styled.div<{ $selected: boolean }>`
|
|
278
|
+
const CharacterRow = styled.div<{ $selected: boolean; $disabled?: boolean }>`
|
|
270
279
|
display: flex;
|
|
271
280
|
align-items: center;
|
|
272
281
|
gap: 12px;
|
|
273
282
|
padding: 10px 12px;
|
|
274
|
-
border: 1px solid ${({ $selected }) => ($selected ? '#f59e0b' : 'rgba(255,255,255,0.08)')};
|
|
283
|
+
border: 1px solid ${({ $selected, $disabled }) => ($disabled ? 'rgba(255,255,255,0.04)' : $selected ? '#f59e0b' : 'rgba(255,255,255,0.08)')};
|
|
275
284
|
border-radius: 6px;
|
|
276
|
-
background: ${({ $selected }) => ($selected ? 'rgba(245,158,11,0.1)' : 'rgba(255,255,255,0.02)')};
|
|
277
|
-
cursor: pointer;
|
|
285
|
+
background: ${({ $selected, $disabled }) => ($disabled ? 'rgba(0,0,0,0.15)' : $selected ? 'rgba(245,158,11,0.1)' : 'rgba(255,255,255,0.02)')};
|
|
286
|
+
cursor: ${({ $disabled }) => ($disabled ? 'not-allowed' : 'pointer')};
|
|
287
|
+
opacity: ${({ $disabled }) => ($disabled ? 0.5 : 1)};
|
|
278
288
|
transition: border-color 0.15s, background 0.15s;
|
|
279
289
|
|
|
280
290
|
&:hover {
|
|
281
|
-
border-color: ${({ $selected }) => ($selected ? '#f59e0b' : 'rgba(245,158,11,0.4)')};
|
|
282
|
-
background: ${({ $selected }) => ($selected ? 'rgba(245,158,11,0.1)' : 'rgba(245,158,11,0.05)')};
|
|
291
|
+
border-color: ${({ $selected, $disabled }) => ($disabled ? 'rgba(255,255,255,0.04)' : $selected ? '#f59e0b' : 'rgba(245,158,11,0.4)')};
|
|
292
|
+
background: ${({ $selected, $disabled }) => ($disabled ? 'rgba(0,0,0,0.15)' : $selected ? 'rgba(245,158,11,0.1)' : 'rgba(245,158,11,0.05)')};
|
|
283
293
|
}
|
|
284
294
|
|
|
285
295
|
&:focus-visible {
|
|
@@ -288,11 +298,11 @@ const CharacterRow = styled.div<{ $selected: boolean }>`
|
|
|
288
298
|
}
|
|
289
299
|
`;
|
|
290
300
|
|
|
291
|
-
const RadioCircle = styled.div<{ $selected: boolean }>`
|
|
301
|
+
const RadioCircle = styled.div<{ $selected: boolean; $disabled?: boolean }>`
|
|
292
302
|
width: 14px;
|
|
293
303
|
height: 14px;
|
|
294
304
|
border-radius: 50%;
|
|
295
|
-
border: 2px solid ${({ $selected }) => ($selected ? '#f59e0b' : 'rgba(255,255,255,0.4)')};
|
|
305
|
+
border: 2px solid ${({ $selected, $disabled }) => ($disabled ? 'rgba(255,255,255,0.15)' : $selected ? '#f59e0b' : 'rgba(255,255,255,0.4)')};
|
|
296
306
|
flex-shrink: 0;
|
|
297
307
|
display: flex;
|
|
298
308
|
align-items: center;
|
|
@@ -303,12 +313,23 @@ const RadioCircle = styled.div<{ $selected: boolean }>`
|
|
|
303
313
|
width: 6px;
|
|
304
314
|
height: 6px;
|
|
305
315
|
border-radius: 50%;
|
|
306
|
-
background: #f59e0b;
|
|
316
|
+
background: ${({ $disabled }) => ($disabled ? 'rgba(255,255,255,0.15)' : '#f59e0b')};
|
|
307
317
|
opacity: ${({ $selected }) => ($selected ? 1 : 0)};
|
|
308
318
|
transition: opacity 0.15s;
|
|
309
319
|
}
|
|
310
320
|
`;
|
|
311
321
|
|
|
322
|
+
const ActiveTag = styled.span`
|
|
323
|
+
font-family: 'Press Start 2P', cursive !important;
|
|
324
|
+
font-size: 0.35rem !important;
|
|
325
|
+
color: #666 !important;
|
|
326
|
+
background: rgba(255,255,255,0.06);
|
|
327
|
+
padding: 3px 6px;
|
|
328
|
+
border-radius: 3px;
|
|
329
|
+
white-space: nowrap;
|
|
330
|
+
margin-left: auto;
|
|
331
|
+
`;
|
|
332
|
+
|
|
312
333
|
const SpriteWrapper = styled.div`
|
|
313
334
|
display: flex;
|
|
314
335
|
align-items: center;
|
|
@@ -336,6 +336,7 @@ export const Marketplace: React.FC<IMarketPlaceProps> = props => {
|
|
|
336
336
|
onCharacterDelist={onCharacterDelist ?? (() => {})}
|
|
337
337
|
accountCharacters={accountCharacters ?? []}
|
|
338
338
|
onCharacterList={onCharacterList ?? (() => {})}
|
|
339
|
+
activeCharacterId={props.characterId}
|
|
339
340
|
atlasJSON={props.atlasJSON}
|
|
340
341
|
atlasIMG={props.atlasIMG}
|
|
341
342
|
characterAtlasJSON={characterAtlasJSON ?? props.atlasJSON}
|
|
@@ -20,6 +20,8 @@ export interface IMyCharacterListingsPanelProps {
|
|
|
20
20
|
/** Characters that can be listed (used for the List a Character modal) */
|
|
21
21
|
accountCharacters: ICharacter[];
|
|
22
22
|
onCharacterList: (characterId: string, price: number) => void;
|
|
23
|
+
/** ID of the currently active character */
|
|
24
|
+
activeCharacterId?: string;
|
|
23
25
|
/** Items atlas — for UI sprites like the DC coin */
|
|
24
26
|
atlasJSON: any;
|
|
25
27
|
atlasIMG: any;
|
|
@@ -39,6 +41,7 @@ export const MyCharacterListingsPanel: React.FC<IMyCharacterListingsPanelProps>
|
|
|
39
41
|
onCharacterDelist,
|
|
40
42
|
accountCharacters,
|
|
41
43
|
onCharacterList,
|
|
44
|
+
activeCharacterId,
|
|
42
45
|
atlasJSON,
|
|
43
46
|
atlasIMG,
|
|
44
47
|
characterAtlasJSON,
|
|
@@ -80,6 +83,7 @@ export const MyCharacterListingsPanel: React.FC<IMyCharacterListingsPanelProps>
|
|
|
80
83
|
isOpen={isListingModalOpen}
|
|
81
84
|
onClose={() => setIsListingModalOpen(false)}
|
|
82
85
|
accountCharacters={accountCharacters}
|
|
86
|
+
activeCharacterId={activeCharacterId}
|
|
83
87
|
atlasJSON={atlasJSON}
|
|
84
88
|
atlasIMG={atlasIMG}
|
|
85
89
|
characterAtlasJSON={characterAtlasJSON}
|