@rpg-engine/long-bow 0.8.188 → 0.8.190
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/MyCharacterListingsPanel.d.ts +4 -1
- package/dist/long-bow.cjs.development.js +238 -246
- 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 +238 -246
- package/dist/long-bow.esm.js.map +1 -1
- package/dist/stories/Features/marketplace/CharacterMarketplace.stories.d.ts +1 -0
- package/package.json +1 -1
- package/src/components/Marketplace/Marketplace.tsx +2 -20
- package/src/components/Marketplace/MyCharacterListingsPanel.tsx +140 -112
- package/src/stories/Features/marketplace/CharacterMarketplace.stories.tsx +45 -1
|
@@ -7,4 +7,5 @@ export declare const CharacterBrowseEmpty: Story;
|
|
|
7
7
|
export declare const CharacterBrowseFiltered: Story;
|
|
8
8
|
export declare const MyCharacterListings: Story;
|
|
9
9
|
export declare const MyCharacterListingsEmpty: Story;
|
|
10
|
+
export declare const MyCharacterListingsNoEligible: Story;
|
|
10
11
|
export declare const CharacterListingPending: Story;
|
package/package.json
CHANGED
|
@@ -32,7 +32,6 @@ import { MarketplacePaymentMethod } from './MarketplaceBuyModal';
|
|
|
32
32
|
import { MarketplaceAcceptedCurrency, MarketplaceSettingsPanel } from './MarketplaceSettingsPanel';
|
|
33
33
|
import { CharacterMarketplacePanel } from './CharacterMarketplacePanel';
|
|
34
34
|
import { MyCharacterListingsPanel } from './MyCharacterListingsPanel';
|
|
35
|
-
import { CharacterListingForm } from './CharacterListingForm';
|
|
36
35
|
|
|
37
36
|
export interface IMarketPlaceProps {
|
|
38
37
|
items: IMarketplaceItem[];
|
|
@@ -206,7 +205,7 @@ export const Marketplace: React.FC<IMarketPlaceProps> = props => {
|
|
|
206
205
|
const [activeTab, setActiveTab] = useState<ActiveTab>('marketplace');
|
|
207
206
|
const [acceptedCurrency, setAcceptedCurrency] = useState<MarketplaceAcceptedCurrency>(acceptedCurrencyProp ?? MarketplaceAcceptedCurrency.GoldOrDc);
|
|
208
207
|
const [isBlueprintSearchOpen, setIsBlueprintSearchOpen] = useState(false);
|
|
209
|
-
const [characterSubTab, setCharacterSubTab] = useState<'browse' | 'my-listings'
|
|
208
|
+
const [characterSubTab, setCharacterSubTab] = useState<'browse' | 'my-listings'>('browse');
|
|
210
209
|
|
|
211
210
|
const handleCurrencyChange = (value: MarketplaceAcceptedCurrency) => {
|
|
212
211
|
setAcceptedCurrency(value);
|
|
@@ -305,13 +304,6 @@ export const Marketplace: React.FC<IMarketPlaceProps> = props => {
|
|
|
305
304
|
>
|
|
306
305
|
My Listings
|
|
307
306
|
</CharacterSubTab>
|
|
308
|
-
<CharacterSubTab
|
|
309
|
-
$active={characterSubTab === 'list'}
|
|
310
|
-
onClick={() => setCharacterSubTab('list')}
|
|
311
|
-
type="button"
|
|
312
|
-
>
|
|
313
|
-
List Character
|
|
314
|
-
</CharacterSubTab>
|
|
315
307
|
</CharacterSubTabs>
|
|
316
308
|
|
|
317
309
|
{characterSubTab === 'browse' && (
|
|
@@ -342,17 +334,6 @@ export const Marketplace: React.FC<IMarketPlaceProps> = props => {
|
|
|
342
334
|
itemsPerPage={10}
|
|
343
335
|
onPageChange={onMyCharacterListingsPageChange ?? (() => {})}
|
|
344
336
|
onCharacterDelist={onCharacterDelist ?? (() => {})}
|
|
345
|
-
atlasJSON={props.atlasJSON}
|
|
346
|
-
atlasIMG={props.atlasIMG}
|
|
347
|
-
characterAtlasJSON={characterAtlasJSON ?? props.atlasJSON}
|
|
348
|
-
characterAtlasIMG={characterAtlasIMG ?? props.atlasIMG}
|
|
349
|
-
enableHotkeys={props.enableHotkeys}
|
|
350
|
-
disableHotkeys={props.disableHotkeys}
|
|
351
|
-
/>
|
|
352
|
-
)}
|
|
353
|
-
|
|
354
|
-
{characterSubTab === 'list' && (
|
|
355
|
-
<CharacterListingForm
|
|
356
337
|
accountCharacters={accountCharacters ?? []}
|
|
357
338
|
onCharacterList={onCharacterList ?? (() => {})}
|
|
358
339
|
atlasJSON={props.atlasJSON}
|
|
@@ -363,6 +344,7 @@ export const Marketplace: React.FC<IMarketPlaceProps> = props => {
|
|
|
363
344
|
disableHotkeys={props.disableHotkeys}
|
|
364
345
|
/>
|
|
365
346
|
)}
|
|
347
|
+
|
|
366
348
|
</>
|
|
367
349
|
)}
|
|
368
350
|
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import { formatDCAmount, ICharacterListing } from '@rpg-engine/shared';
|
|
1
|
+
import { formatDCAmount, ICharacter, ICharacterListing } from '@rpg-engine/shared';
|
|
2
2
|
import { Delete } from 'pixelarticons/react/Delete';
|
|
3
|
+
import { ShoppingBag } from 'pixelarticons/react/ShoppingBag';
|
|
3
4
|
import { User } from 'pixelarticons/react/User';
|
|
4
5
|
import React, { useEffect, useRef, useState } from 'react';
|
|
5
6
|
import styled from 'styled-components';
|
|
6
7
|
import { ConfirmModal } from '../ConfirmModal';
|
|
8
|
+
import { Pagination } from '../shared/Pagination/Pagination';
|
|
7
9
|
import { SpriteFromAtlas } from '../shared/SpriteFromAtlas';
|
|
8
10
|
import { CTAButton } from '../shared/CTAButton/CTAButton';
|
|
11
|
+
import { CharacterListingModal } from './CharacterListingModal';
|
|
9
12
|
|
|
10
13
|
export interface IMyCharacterListingsPanelProps {
|
|
11
14
|
myCharacterListings: ICharacterListing[];
|
|
@@ -14,6 +17,9 @@ export interface IMyCharacterListingsPanelProps {
|
|
|
14
17
|
itemsPerPage: number;
|
|
15
18
|
onPageChange: (page: number) => void;
|
|
16
19
|
onCharacterDelist: (listingId: string) => void;
|
|
20
|
+
/** Characters that can be listed (used for the List a Character modal) */
|
|
21
|
+
accountCharacters: ICharacter[];
|
|
22
|
+
onCharacterList: (characterId: string, price: number) => void;
|
|
17
23
|
/** Items atlas — for UI sprites like the DC coin */
|
|
18
24
|
atlasJSON: any;
|
|
19
25
|
atlasIMG: any;
|
|
@@ -31,60 +37,81 @@ export const MyCharacterListingsPanel: React.FC<IMyCharacterListingsPanelProps>
|
|
|
31
37
|
itemsPerPage,
|
|
32
38
|
onPageChange,
|
|
33
39
|
onCharacterDelist,
|
|
40
|
+
accountCharacters,
|
|
41
|
+
onCharacterList,
|
|
34
42
|
atlasJSON,
|
|
35
43
|
atlasIMG,
|
|
36
44
|
characterAtlasJSON,
|
|
37
45
|
characterAtlasIMG,
|
|
38
46
|
enableHotkeys,
|
|
47
|
+
disableHotkeys,
|
|
39
48
|
}) => {
|
|
40
|
-
const [
|
|
49
|
+
const [delistingId, setDelistingId] = useState<string | null>(null);
|
|
50
|
+
const [isListingModalOpen, setIsListingModalOpen] = useState(false);
|
|
41
51
|
const itemsContainer = useRef<HTMLDivElement>(null);
|
|
42
52
|
|
|
43
53
|
useEffect(() => {
|
|
44
54
|
itemsContainer.current?.scrollTo(0, 0);
|
|
45
55
|
}, [currentPage]);
|
|
46
56
|
|
|
47
|
-
const handleDelistClick = (listingId: string) => {
|
|
48
|
-
setDelistingListingId(listingId);
|
|
49
|
-
};
|
|
50
|
-
|
|
51
57
|
const handleDelistConfirm = () => {
|
|
52
|
-
if (
|
|
53
|
-
onCharacterDelist(
|
|
54
|
-
|
|
58
|
+
if (delistingId) {
|
|
59
|
+
onCharacterDelist(delistingId);
|
|
60
|
+
setDelistingId(null);
|
|
55
61
|
enableHotkeys?.();
|
|
56
62
|
}
|
|
57
63
|
};
|
|
58
64
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
};
|
|
65
|
+
const eligibleCount = accountCharacters.filter(
|
|
66
|
+
c => !c.isListedForSale && !c.tradedAt
|
|
67
|
+
).length;
|
|
63
68
|
|
|
64
69
|
return (
|
|
65
70
|
<>
|
|
66
|
-
{
|
|
71
|
+
{delistingId && (
|
|
67
72
|
<ConfirmModal
|
|
68
|
-
onClose={() => {
|
|
69
|
-
setDelistingListingId(null);
|
|
70
|
-
enableHotkeys?.();
|
|
71
|
-
}}
|
|
73
|
+
onClose={() => { setDelistingId(null); enableHotkeys?.(); }}
|
|
72
74
|
onConfirm={handleDelistConfirm}
|
|
73
75
|
message="Are you sure you want to delist this character?"
|
|
74
76
|
/>
|
|
75
77
|
)}
|
|
76
78
|
|
|
77
|
-
<
|
|
79
|
+
<CharacterListingModal
|
|
80
|
+
isOpen={isListingModalOpen}
|
|
81
|
+
onClose={() => setIsListingModalOpen(false)}
|
|
82
|
+
accountCharacters={accountCharacters}
|
|
83
|
+
atlasJSON={atlasJSON}
|
|
84
|
+
atlasIMG={atlasIMG}
|
|
85
|
+
characterAtlasJSON={characterAtlasJSON}
|
|
86
|
+
characterAtlasIMG={characterAtlasIMG}
|
|
87
|
+
onCharacterList={(id, price) => {
|
|
88
|
+
onCharacterList(id, price);
|
|
89
|
+
setIsListingModalOpen(false);
|
|
90
|
+
}}
|
|
91
|
+
enableHotkeys={enableHotkeys}
|
|
92
|
+
disableHotkeys={disableHotkeys}
|
|
93
|
+
/>
|
|
94
|
+
|
|
95
|
+
<Toolbar>
|
|
96
|
+
<ListCharacterBtn
|
|
97
|
+
icon={<ShoppingBag width={16} height={16} />}
|
|
98
|
+
label={`List a Character${eligibleCount > 0 ? ` (${eligibleCount} eligible)` : ''}`}
|
|
99
|
+
onClick={() => setIsListingModalOpen(true)}
|
|
100
|
+
disabled={eligibleCount === 0}
|
|
101
|
+
/>
|
|
102
|
+
</Toolbar>
|
|
103
|
+
|
|
104
|
+
<ListingsContainer ref={itemsContainer}>
|
|
78
105
|
{myCharacterListings.length === 0 ? (
|
|
79
106
|
<EmptyState>
|
|
80
107
|
<User width={32} height={32} />
|
|
81
|
-
<EmptyText>
|
|
82
|
-
<EmptySubtext>Use the "List Character" tab to
|
|
108
|
+
<EmptyText>No listed characters.</EmptyText>
|
|
109
|
+
<EmptySubtext>Use the "List Character" tab to put a character up for sale.</EmptySubtext>
|
|
83
110
|
</EmptyState>
|
|
84
111
|
) : (
|
|
85
112
|
<ListingsGrid>
|
|
86
113
|
{myCharacterListings.map((listing) => (
|
|
87
|
-
<CharacterListingCard key={listing._id}>
|
|
114
|
+
<CharacterListingCard key={listing._id} $isBeingBought={listing.isBeingBought}>
|
|
88
115
|
<CharacterSprite>
|
|
89
116
|
<SpriteFromAtlas
|
|
90
117
|
atlasIMG={characterAtlasIMG}
|
|
@@ -98,7 +125,9 @@ export const MyCharacterListingsPanel: React.FC<IMyCharacterListingsPanelProps>
|
|
|
98
125
|
</CharacterSprite>
|
|
99
126
|
<CharacterInfo>
|
|
100
127
|
<CharacterName>{listing.characterSnapshot.name || 'Unknown'}</CharacterName>
|
|
101
|
-
<CharacterMeta>
|
|
128
|
+
<CharacterMeta>
|
|
129
|
+
Lv.{listing.characterSnapshot.level} · {listing.characterSnapshot.class}
|
|
130
|
+
</CharacterMeta>
|
|
102
131
|
<ListingPrice>
|
|
103
132
|
<DCCoinWrapper>
|
|
104
133
|
<SpriteFromAtlas
|
|
@@ -111,18 +140,19 @@ export const MyCharacterListingsPanel: React.FC<IMyCharacterListingsPanelProps>
|
|
|
111
140
|
</DCCoinWrapper>
|
|
112
141
|
{formatDCAmount(listing.price)} DC
|
|
113
142
|
</ListingPrice>
|
|
114
|
-
<
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
)}
|
|
143
|
+
<ListingDate>
|
|
144
|
+
Listed {new Date(listing.createdAt).toLocaleDateString()}
|
|
145
|
+
</ListingDate>
|
|
118
146
|
</CharacterInfo>
|
|
119
|
-
<
|
|
120
|
-
icon={<Delete width={
|
|
147
|
+
<DelistBtn
|
|
148
|
+
icon={<Delete width={14} height={14} />}
|
|
121
149
|
label="Delist"
|
|
122
|
-
onClick={() =>
|
|
123
|
-
iconColor="#ef4444"
|
|
150
|
+
onClick={() => setDelistingId(listing._id)}
|
|
124
151
|
disabled={listing.isBeingBought}
|
|
125
152
|
/>
|
|
153
|
+
{listing.isBeingBought && (
|
|
154
|
+
<PendingBadge>Pending</PendingBadge>
|
|
155
|
+
)}
|
|
126
156
|
</CharacterListingCard>
|
|
127
157
|
))}
|
|
128
158
|
</ListingsGrid>
|
|
@@ -131,18 +161,11 @@ export const MyCharacterListingsPanel: React.FC<IMyCharacterListingsPanelProps>
|
|
|
131
161
|
|
|
132
162
|
{totalCount > itemsPerPage && (
|
|
133
163
|
<PagerFooter>
|
|
134
|
-
<Pagination
|
|
135
|
-
{
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
type="button"
|
|
140
|
-
onClick={() => onPageChange(page)}
|
|
141
|
-
>
|
|
142
|
-
{page}
|
|
143
|
-
</PageButton>
|
|
144
|
-
))}
|
|
145
|
-
</Pagination>
|
|
164
|
+
<Pagination
|
|
165
|
+
currentPage={currentPage}
|
|
166
|
+
totalPages={Math.ceil(totalCount / itemsPerPage)}
|
|
167
|
+
onPageChange={onPageChange}
|
|
168
|
+
/>
|
|
146
169
|
</PagerFooter>
|
|
147
170
|
)}
|
|
148
171
|
</>
|
|
@@ -171,15 +194,26 @@ const ListingsGrid = styled.div`
|
|
|
171
194
|
padding: 12px;
|
|
172
195
|
`;
|
|
173
196
|
|
|
174
|
-
const CharacterListingCard = styled.div
|
|
197
|
+
const CharacterListingCard = styled.div<{ $isBeingBought?: boolean }>`
|
|
175
198
|
display: flex;
|
|
176
199
|
flex-direction: column;
|
|
177
200
|
align-items: center;
|
|
178
201
|
gap: 8px;
|
|
179
202
|
background: rgba(255, 255, 255, 0.03);
|
|
180
|
-
border: 1px solid
|
|
203
|
+
border: 1px solid ${({ $isBeingBought }) =>
|
|
204
|
+
$isBeingBought ? 'rgba(239,68,68,0.3)' : 'rgba(255,255,255,0.08)'};
|
|
181
205
|
border-radius: 8px;
|
|
182
206
|
padding: 12px;
|
|
207
|
+
position: relative;
|
|
208
|
+
opacity: ${({ $isBeingBought }) => ($isBeingBought ? 0.7 : 1)};
|
|
209
|
+
transition: border-color 0.15s, background 0.15s;
|
|
210
|
+
|
|
211
|
+
&:hover {
|
|
212
|
+
border-color: ${({ $isBeingBought }) =>
|
|
213
|
+
$isBeingBought ? 'rgba(239,68,68,0.5)' : 'rgba(245,158,11,0.3)'};
|
|
214
|
+
background: ${({ $isBeingBought }) =>
|
|
215
|
+
$isBeingBought ? 'rgba(239,68,68,0.04)' : 'rgba(245,158,11,0.04)'};
|
|
216
|
+
}
|
|
183
217
|
`;
|
|
184
218
|
|
|
185
219
|
const CharacterSprite = styled.div`
|
|
@@ -187,6 +221,9 @@ const CharacterSprite = styled.div`
|
|
|
187
221
|
align-items: center;
|
|
188
222
|
justify-content: center;
|
|
189
223
|
image-rendering: pixelated;
|
|
224
|
+
width: 64px;
|
|
225
|
+
height: 64px;
|
|
226
|
+
flex-shrink: 0;
|
|
190
227
|
`;
|
|
191
228
|
|
|
192
229
|
const CharacterInfo = styled.div`
|
|
@@ -195,19 +232,21 @@ const CharacterInfo = styled.div`
|
|
|
195
232
|
align-items: center;
|
|
196
233
|
gap: 4px;
|
|
197
234
|
text-align: center;
|
|
235
|
+
width: 100%;
|
|
198
236
|
`;
|
|
199
237
|
|
|
200
238
|
const CharacterName = styled.span`
|
|
201
|
-
font-family: 'Press Start 2P', cursive;
|
|
202
|
-
font-size: 0.55rem;
|
|
203
|
-
color: #f3f4f6;
|
|
239
|
+
font-family: 'Press Start 2P', cursive !important;
|
|
240
|
+
font-size: 0.55rem !important;
|
|
241
|
+
color: #f3f4f6 !important;
|
|
204
242
|
text-transform: uppercase;
|
|
205
243
|
letter-spacing: 0.5px;
|
|
206
244
|
`;
|
|
207
245
|
|
|
208
246
|
const CharacterMeta = styled.span`
|
|
209
|
-
font-
|
|
210
|
-
|
|
247
|
+
font-family: 'Press Start 2P', cursive !important;
|
|
248
|
+
font-size: 0.45rem !important;
|
|
249
|
+
color: #888 !important;
|
|
211
250
|
text-transform: uppercase;
|
|
212
251
|
letter-spacing: 0.5px;
|
|
213
252
|
`;
|
|
@@ -215,10 +254,12 @@ const CharacterMeta = styled.span`
|
|
|
215
254
|
const ListingPrice = styled.div`
|
|
216
255
|
display: flex;
|
|
217
256
|
align-items: center;
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
font-
|
|
221
|
-
|
|
257
|
+
justify-content: center;
|
|
258
|
+
gap: 4px;
|
|
259
|
+
font-family: 'Press Start 2P', cursive !important;
|
|
260
|
+
font-size: 0.5rem !important;
|
|
261
|
+
color: #fef08a !important;
|
|
262
|
+
line-height: 1;
|
|
222
263
|
`;
|
|
223
264
|
|
|
224
265
|
const DCCoinWrapper = styled.span`
|
|
@@ -226,48 +267,55 @@ const DCCoinWrapper = styled.span`
|
|
|
226
267
|
align-items: center;
|
|
227
268
|
justify-content: center;
|
|
228
269
|
flex-shrink: 0;
|
|
270
|
+
line-height: 0;
|
|
229
271
|
`;
|
|
230
272
|
|
|
231
|
-
const
|
|
232
|
-
font-
|
|
233
|
-
|
|
273
|
+
const ListingDate = styled.span`
|
|
274
|
+
font-family: 'Press Start 2P', cursive !important;
|
|
275
|
+
font-size: 0.35rem !important;
|
|
276
|
+
color: #52525b !important;
|
|
234
277
|
text-transform: uppercase;
|
|
235
278
|
letter-spacing: 0.5px;
|
|
236
279
|
`;
|
|
237
280
|
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
padding:
|
|
281
|
+
const DelistBtn = styled(CTAButton)`
|
|
282
|
+
width: 100%;
|
|
283
|
+
padding: 6px 10px;
|
|
284
|
+
height: 28px;
|
|
285
|
+
margin-top: 2px;
|
|
286
|
+
|
|
287
|
+
span { font-size: 0.48rem; }
|
|
288
|
+
svg { font-size: 0.9rem; }
|
|
289
|
+
`;
|
|
290
|
+
|
|
291
|
+
const PendingBadge = styled.span`
|
|
292
|
+
position: absolute;
|
|
293
|
+
top: 6px;
|
|
294
|
+
right: 6px;
|
|
295
|
+
background: rgba(239, 68, 68, 0.2);
|
|
296
|
+
border: 1px solid rgba(239, 68, 68, 0.4);
|
|
241
297
|
border-radius: 4px;
|
|
298
|
+
padding: 2px 6px;
|
|
299
|
+
font-family: 'Press Start 2P', cursive !important;
|
|
300
|
+
font-size: 0.35rem !important;
|
|
301
|
+
color: #ef4444 !important;
|
|
242
302
|
text-transform: uppercase;
|
|
243
303
|
letter-spacing: 0.5px;
|
|
244
|
-
${({ $status }) =>
|
|
245
|
-
$status === 'pending'
|
|
246
|
-
? `
|
|
247
|
-
background: rgba(239, 68, 68, 0.2);
|
|
248
|
-
border: 1px solid rgba(239, 68, 68, 0.4);
|
|
249
|
-
color: #ef4444;
|
|
250
|
-
`
|
|
251
|
-
: `
|
|
252
|
-
background: rgba(34, 197, 94, 0.2);
|
|
253
|
-
border: 1px solid rgba(34, 197, 94, 0.4);
|
|
254
|
-
color: #22c55e;
|
|
255
|
-
`}
|
|
256
304
|
`;
|
|
257
305
|
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
306
|
+
const Toolbar = styled.div`
|
|
307
|
+
width: 95%;
|
|
308
|
+
margin: 10px auto 0 auto;
|
|
309
|
+
display: flex;
|
|
310
|
+
justify-content: flex-end;
|
|
311
|
+
`;
|
|
263
312
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
313
|
+
const ListCharacterBtn = styled(CTAButton)`
|
|
314
|
+
padding: 8px 16px;
|
|
315
|
+
height: 32px;
|
|
267
316
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
}
|
|
317
|
+
span { font-size: 0.5rem; }
|
|
318
|
+
svg { font-size: 1rem; }
|
|
271
319
|
`;
|
|
272
320
|
|
|
273
321
|
const PagerFooter = styled.div`
|
|
@@ -280,28 +328,6 @@ const PagerFooter = styled.div`
|
|
|
280
328
|
margin: 0 auto;
|
|
281
329
|
`;
|
|
282
330
|
|
|
283
|
-
const Pagination = styled.div`
|
|
284
|
-
display: flex;
|
|
285
|
-
gap: 6px;
|
|
286
|
-
`;
|
|
287
|
-
|
|
288
|
-
const PageButton = styled.button<{ $active: boolean }>`
|
|
289
|
-
padding: 6px 10px;
|
|
290
|
-
font-family: 'Press Start 2P', cursive;
|
|
291
|
-
font-size: 0.5rem;
|
|
292
|
-
border-radius: 4px;
|
|
293
|
-
border: 1px solid ${({ $active }) => ($active ? '#f59e0b' : 'rgba(255,255,255,0.12)')};
|
|
294
|
-
background: ${({ $active }) => ($active ? 'rgba(245,158,11,0.15)' : 'rgba(0,0,0,0.3)')};
|
|
295
|
-
color: ${({ $active }) => ($active ? '#f59e0b' : '#777')};
|
|
296
|
-
cursor: pointer;
|
|
297
|
-
transition: border-color 0.15s, background 0.15s, color 0.15s;
|
|
298
|
-
|
|
299
|
-
&:hover {
|
|
300
|
-
border-color: ${({ $active }) => ($active ? '#f59e0b' : 'rgba(255,255,255,0.3)')};
|
|
301
|
-
color: ${({ $active }) => ($active ? '#f59e0b' : '#bbb')};
|
|
302
|
-
}
|
|
303
|
-
`;
|
|
304
|
-
|
|
305
331
|
const EmptyState = styled.div`
|
|
306
332
|
display: flex;
|
|
307
333
|
flex-direction: column;
|
|
@@ -313,17 +339,19 @@ const EmptyState = styled.div`
|
|
|
313
339
|
`;
|
|
314
340
|
|
|
315
341
|
const EmptyText = styled.span`
|
|
316
|
-
font-
|
|
317
|
-
|
|
342
|
+
font-family: 'Press Start 2P', cursive !important;
|
|
343
|
+
font-size: 0.48rem !important;
|
|
344
|
+
color: #71717a !important;
|
|
318
345
|
text-transform: uppercase;
|
|
319
346
|
letter-spacing: 1px;
|
|
320
347
|
`;
|
|
321
348
|
|
|
322
349
|
const EmptySubtext = styled.span`
|
|
323
|
-
font-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
letter-spacing: 0.5px;
|
|
350
|
+
font-family: 'Press Start 2P', cursive !important;
|
|
351
|
+
font-size: 0.38rem !important;
|
|
352
|
+
color: #52525b !important;
|
|
327
353
|
text-align: center;
|
|
328
|
-
max-width:
|
|
354
|
+
max-width: 260px;
|
|
355
|
+
line-height: 1.6;
|
|
329
356
|
`;
|
|
357
|
+
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ICharacterListing } from '@rpg-engine/shared';
|
|
1
|
+
import { ICharacter, ICharacterListing } from '@rpg-engine/shared';
|
|
2
2
|
import { Meta, Story } from '@storybook/react';
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import { RPGUIRoot } from '../../..';
|
|
@@ -189,6 +189,25 @@ const mockMyCharacterListings: ICharacterListing[] = [
|
|
|
189
189
|
},
|
|
190
190
|
];
|
|
191
191
|
|
|
192
|
+
const mockAccountCharacters: ICharacter[] = [
|
|
193
|
+
{
|
|
194
|
+
_id: 'char-a1',
|
|
195
|
+
name: 'MyRogue',
|
|
196
|
+
textureKey: 'redhair-girl-1',
|
|
197
|
+
isListedForSale: false,
|
|
198
|
+
tradedAt: undefined,
|
|
199
|
+
skills: { level: 22 } as any,
|
|
200
|
+
} as ICharacter,
|
|
201
|
+
{
|
|
202
|
+
_id: 'char-a2',
|
|
203
|
+
name: 'MyPaladin',
|
|
204
|
+
textureKey: 'dragon-knight',
|
|
205
|
+
isListedForSale: false,
|
|
206
|
+
tradedAt: undefined,
|
|
207
|
+
skills: { level: 38 } as any,
|
|
208
|
+
} as ICharacter,
|
|
209
|
+
];
|
|
210
|
+
|
|
192
211
|
export const CharacterBrowse: Story = () => (
|
|
193
212
|
<RPGUIRoot>
|
|
194
213
|
<CharacterMarketplacePanel
|
|
@@ -288,6 +307,8 @@ export const MyCharacterListings: Story = () => (
|
|
|
288
307
|
itemsPerPage={8}
|
|
289
308
|
onPageChange={() => {}}
|
|
290
309
|
onCharacterDelist={() => {}}
|
|
310
|
+
accountCharacters={mockAccountCharacters}
|
|
311
|
+
onCharacterList={() => {}}
|
|
291
312
|
atlasJSON={itemsAtlasJSON}
|
|
292
313
|
atlasIMG={itemsAtlasIMG}
|
|
293
314
|
characterAtlasJSON={entitiesAtlasJSON}
|
|
@@ -307,6 +328,8 @@ export const MyCharacterListingsEmpty: Story = () => (
|
|
|
307
328
|
itemsPerPage={8}
|
|
308
329
|
onPageChange={() => {}}
|
|
309
330
|
onCharacterDelist={() => {}}
|
|
331
|
+
accountCharacters={mockAccountCharacters}
|
|
332
|
+
onCharacterList={() => {}}
|
|
310
333
|
atlasJSON={itemsAtlasJSON}
|
|
311
334
|
atlasIMG={itemsAtlasIMG}
|
|
312
335
|
characterAtlasJSON={entitiesAtlasJSON}
|
|
@@ -317,6 +340,27 @@ export const MyCharacterListingsEmpty: Story = () => (
|
|
|
317
340
|
|
|
318
341
|
MyCharacterListingsEmpty.storyName = 'My Listings - Empty State';
|
|
319
342
|
|
|
343
|
+
export const MyCharacterListingsNoEligible: Story = () => (
|
|
344
|
+
<RPGUIRoot>
|
|
345
|
+
<MyCharacterListingsPanel
|
|
346
|
+
myCharacterListings={mockMyCharacterListings}
|
|
347
|
+
totalCount={2}
|
|
348
|
+
currentPage={1}
|
|
349
|
+
itemsPerPage={8}
|
|
350
|
+
onPageChange={() => {}}
|
|
351
|
+
onCharacterDelist={() => {}}
|
|
352
|
+
accountCharacters={[]}
|
|
353
|
+
onCharacterList={() => {}}
|
|
354
|
+
atlasJSON={itemsAtlasJSON}
|
|
355
|
+
atlasIMG={itemsAtlasIMG}
|
|
356
|
+
characterAtlasJSON={entitiesAtlasJSON}
|
|
357
|
+
characterAtlasIMG={entitiesAtlasIMG}
|
|
358
|
+
/>
|
|
359
|
+
</RPGUIRoot>
|
|
360
|
+
);
|
|
361
|
+
|
|
362
|
+
MyCharacterListingsNoEligible.storyName = 'My Listings - No eligible chars to list';
|
|
363
|
+
|
|
320
364
|
export const CharacterListingPending: Story = () => (
|
|
321
365
|
<RPGUIRoot>
|
|
322
366
|
<CharacterMarketplacePanel
|