@rpg-engine/long-bow 0.8.167 → 0.8.168

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.
@@ -3,3 +3,4 @@ declare const meta: Meta;
3
3
  export default meta;
4
4
  export declare const Default: import("@storybook/csf").AnnotatedStoryFn<import("@storybook/react").ReactFramework, import("@storybook/react").Args>;
5
5
  export declare const HighStackQuantity: Story;
6
+ export declare const DCOnly: Story;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpg-engine/long-bow",
3
- "version": "0.8.167",
3
+ "version": "0.8.168",
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.10.93",
87
+ "@rpg-engine/shared": "0.10.100",
88
88
  "dayjs": "^1.11.2",
89
89
  "font-awesome": "^4.7.0",
90
90
  "fs-extra": "^10.1.0",
@@ -3,6 +3,7 @@ import {
3
3
  IEquipmentSet,
4
4
  IMarketplaceBuyOrderItem,
5
5
  IMarketplaceItem,
6
+ MarketplaceAcceptedCurrency,
6
7
  MarketplaceBuyOrderStatus,
7
8
  } from '@rpg-engine/shared';
8
9
  import React, { useEffect, useMemo, useRef, useState } from 'react';
@@ -112,6 +113,7 @@ export const BuyPanel: React.FC<IBuyPanelProps> = ({
112
113
  ]);
113
114
  const [buyingItemId, setBuyingItemId] = useState<string | null>(null);
114
115
  const [fulfillingBuyOrderId, setFulfillingBuyOrderId] = useState<string | null>(null);
116
+ const [currencyFilter, setCurrencyFilter] = useState<'gold' | 'dc' | null>(null);
115
117
 
116
118
  const itemsContainer = useRef<HTMLDivElement>(null);
117
119
 
@@ -127,9 +129,23 @@ export const BuyPanel: React.FC<IBuyPanelProps> = ({
127
129
  const getDCEquivalentPrice = (goldPrice: number): number =>
128
130
  dcToGoldSwapRate > 0 ? goldToDC(goldPrice) : 0;
129
131
 
132
+ const handleBuyClick = (listingId: string): void => {
133
+ // All currencies go through the confirmation modal
134
+ setBuyingItemId(listingId);
135
+ };
136
+
130
137
  const groupedItems = useMemo(() => {
138
+ const filtered = currencyFilter === null
139
+ ? items
140
+ : items.filter(i => {
141
+ const c = i.acceptedCurrency || MarketplaceAcceptedCurrency.GoldOrDc;
142
+ if (currencyFilter === 'gold') return c === MarketplaceAcceptedCurrency.Gold || c === MarketplaceAcceptedCurrency.GoldOrDc;
143
+ if (currencyFilter === 'dc') return c === MarketplaceAcceptedCurrency.Dc || c === MarketplaceAcceptedCurrency.GoldOrDc;
144
+ return true;
145
+ });
146
+
131
147
  const groups = new Map<string, IMarketplaceItem[]>();
132
- for (const entry of items) {
148
+ for (const entry of filtered) {
133
149
  const key = entry.item.key;
134
150
  if (!groups.has(key)) {
135
151
  groups.set(key, []);
@@ -143,7 +159,7 @@ export const BuyPanel: React.FC<IBuyPanelProps> = ({
143
159
  otherListings: sorted.slice(1),
144
160
  };
145
161
  });
146
- }, [items]);
162
+ }, [items, currencyFilter]);
147
163
 
148
164
  const visibleBuyOrders = useMemo(() => {
149
165
  const normalizedName = name.trim().toLowerCase();
@@ -199,30 +215,36 @@ export const BuyPanel: React.FC<IBuyPanelProps> = ({
199
215
 
200
216
  return (
201
217
  <>
202
- {buyingItemId && buyingItem && hasDCBalance && (
203
- <MarketplaceBuyModal
204
- goldPrice={buyingItem.price}
205
- dcEquivalentPrice={getDCEquivalentPrice(buyingItem.price)}
206
- dcBalance={dcBalance}
207
- onClose={() => setBuyingItemId(null)}
208
- onConfirm={(paymentMethod) => {
209
- onMarketPlaceItemBuy?.(buyingItemId, paymentMethod);
210
- setBuyingItemId(null);
211
- enableHotkeys?.();
212
- }}
213
- />
214
- )}
215
- {buyingItemId && !hasDCBalance && (
216
- <ConfirmModal
217
- onClose={setBuyingItemId.bind(null, null)}
218
- onConfirm={() => {
219
- onMarketPlaceItemBuy?.(buyingItemId);
220
- setBuyingItemId(null);
221
- enableHotkeys?.();
222
- }}
223
- message="Are you sure you want to buy this item?"
224
- />
225
- )}
218
+ {buyingItemId && buyingItem && (() => {
219
+ const listingCurrency = buyingItem.acceptedCurrency || MarketplaceAcceptedCurrency.GoldOrDc;
220
+ const isDcOnly = listingCurrency === MarketplaceAcceptedCurrency.Dc;
221
+ const showPaymentChoiceModal = listingCurrency === MarketplaceAcceptedCurrency.GoldOrDc && hasDCBalance;
222
+ return showPaymentChoiceModal ? (
223
+ <MarketplaceBuyModal
224
+ goldPrice={buyingItem.price}
225
+ dcEquivalentPrice={getDCEquivalentPrice(buyingItem.price)}
226
+ dcBalance={dcBalance}
227
+ onClose={() => setBuyingItemId(null)}
228
+ onConfirm={(paymentMethod) => {
229
+ onMarketPlaceItemBuy?.(buyingItemId, paymentMethod);
230
+ setBuyingItemId(null);
231
+ enableHotkeys?.();
232
+ }}
233
+ />
234
+ ) : (
235
+ <ConfirmModal
236
+ onClose={setBuyingItemId.bind(null, null)}
237
+ onConfirm={() => {
238
+ onMarketPlaceItemBuy?.(buyingItemId, isDcOnly ? 'dc' : undefined);
239
+ setBuyingItemId(null);
240
+ enableHotkeys?.();
241
+ }}
242
+ message={isDcOnly
243
+ ? "Are you sure you want to buy this item with DC?"
244
+ : "Are you sure you want to buy this item?"}
245
+ />
246
+ );
247
+ })()}
226
248
  {fulfillingBuyOrderId && (
227
249
  <ConfirmModal
228
250
  onClose={setFulfillingBuyOrderId.bind(null, null)}
@@ -270,6 +292,22 @@ export const BuyPanel: React.FC<IBuyPanelProps> = ({
270
292
  </FilterButton>
271
293
  </ToolbarRow>
272
294
 
295
+ {showSellSection && (
296
+ <CurrencyFilterRow>
297
+ <CurrencyFilterLabel>Currency:</CurrencyFilterLabel>
298
+ {(['gold', 'dc'] as const).map(c => (
299
+ <CurrencyFilterButton
300
+ key={c}
301
+ $active={currencyFilter === c}
302
+ onPointerDown={() => setCurrencyFilter(prev => prev === c ? null : c)}
303
+ type="button"
304
+ >
305
+ {c === 'gold' ? 'Gold' : 'DC'}
306
+ </CurrencyFilterButton>
307
+ ))}
308
+ </CurrencyFilterRow>
309
+ )}
310
+
273
311
  {showFilters && (
274
312
  <OptionsWrapper showFilters={showFilters}>
275
313
  <WrapperContainer $sell={showSellSection}>
@@ -430,7 +468,7 @@ export const BuyPanel: React.FC<IBuyPanelProps> = ({
430
468
  dcToGoldSwapRate={dcToGoldSwapRate}
431
469
  getDCEquivalentPrice={getDCEquivalentPrice}
432
470
  characterId={characterId}
433
- onBuy={setBuyingItemId}
471
+ onBuy={handleBuyClick}
434
472
  onDCCoinClick={onDCCoinClick}
435
473
  />
436
474
  ))
@@ -708,3 +746,36 @@ const LoadingText = styled.span`
708
746
  text-transform: uppercase;
709
747
  letter-spacing: 1px;
710
748
  `;
749
+
750
+ const CurrencyFilterRow = styled.div`
751
+ display: flex;
752
+ align-items: center;
753
+ gap: 6px;
754
+ width: 95%;
755
+ margin: 0 auto 8px auto;
756
+ `;
757
+
758
+ const CurrencyFilterLabel = styled.span`
759
+ font-size: 0.45rem !important;
760
+ color: #666 !important;
761
+ text-transform: uppercase;
762
+ letter-spacing: 0.5px;
763
+ white-space: nowrap;
764
+ `;
765
+
766
+ const CurrencyFilterButton = styled.button<{ $active: boolean }>`
767
+ padding: 3px 8px;
768
+ font-family: 'Press Start 2P', cursive !important;
769
+ font-size: 0.4rem !important;
770
+ border-radius: 4px;
771
+ border: 1px solid ${({ $active }) => ($active ? '#f59e0b' : 'rgba(255,255,255,0.12)')} !important;
772
+ background: ${({ $active }) => ($active ? 'rgba(245,158,11,0.15)' : 'rgba(0,0,0,0.3)')} !important;
773
+ color: ${({ $active }) => ($active ? '#f59e0b' : '#777')} !important;
774
+ cursor: pointer;
775
+ transition: border-color 0.15s, background 0.15s, color 0.15s;
776
+
777
+ &:hover {
778
+ border-color: ${({ $active }) => ($active ? '#f59e0b' : 'rgba(255,255,255,0.3)')} !important;
779
+ color: ${({ $active }) => ($active ? '#f59e0b' : '#bbb')} !important;
780
+ }
781
+ `;
@@ -29,6 +29,12 @@ export interface IManagmentPanelProps {
29
29
  currentPage: number;
30
30
  }
31
31
 
32
+ const LISTING_CURRENCY_OPTIONS: { value: MarketplaceAcceptedCurrency; label: string }[] = [
33
+ { value: MarketplaceAcceptedCurrency.GoldOrDc, label: 'Both' },
34
+ { value: MarketplaceAcceptedCurrency.Gold, label: 'Gold' },
35
+ { value: MarketplaceAcceptedCurrency.Dc, label: 'DC' },
36
+ ];
37
+
32
38
  export const ManagmentPanel: React.FC<IManagmentPanelProps> = ({
33
39
  items,
34
40
  atlasIMG,
@@ -49,6 +55,9 @@ export const ManagmentPanel: React.FC<IManagmentPanelProps> = ({
49
55
  const [price, setPrice] = useState('');
50
56
  const [isCreatingOffer, setIsCreatingOffer] = useState(false);
51
57
  const [removingItemId, setRemovingItemId] = useState<string | null>(null);
58
+ const [listingCurrency, setListingCurrency] = useState<MarketplaceAcceptedCurrency>(
59
+ acceptedCurrency || MarketplaceAcceptedCurrency.GoldOrDc
60
+ );
52
61
 
53
62
  const itemsContainer = useRef<HTMLDivElement>(null);
54
63
 
@@ -63,7 +72,7 @@ export const ManagmentPanel: React.FC<IManagmentPanelProps> = ({
63
72
  onClose={setIsCreatingOffer.bind(null, false)}
64
73
  onConfirm={() => {
65
74
  if (selectedItemToSell && price && Number(price)) {
66
- onAddItemToMarketplace(selectedItemToSell, Number(price), acceptedCurrency);
75
+ onAddItemToMarketplace(selectedItemToSell, Number(price), listingCurrency);
67
76
  setPrice('');
68
77
  onSelectedItemToSellRemove(selectedItemToSell);
69
78
  setIsCreatingOffer(false);
@@ -124,6 +133,19 @@ export const ManagmentPanel: React.FC<IManagmentPanelProps> = ({
124
133
  }}
125
134
  />
126
135
  </Flex>
136
+ <CurrencyToggleRow>
137
+ <CurrencyToggleLabel>Accept:</CurrencyToggleLabel>
138
+ {LISTING_CURRENCY_OPTIONS.map(opt => (
139
+ <CurrencyToggleButton
140
+ key={opt.value}
141
+ $active={listingCurrency === opt.value}
142
+ onPointerDown={() => setListingCurrency(opt.value)}
143
+ type="button"
144
+ >
145
+ {opt.label}
146
+ </CurrencyToggleButton>
147
+ ))}
148
+ </CurrencyToggleRow>
127
149
  </PriceInputWrapper>
128
150
  </Flex>
129
151
  </InnerOptionsWrapper>
@@ -169,13 +191,14 @@ export const ManagmentPanel: React.FC<IManagmentPanelProps> = ({
169
191
  </OptionsWrapper>
170
192
 
171
193
  <ItemComponentScrollWrapper id="MarketContainer" ref={itemsContainer}>
172
- {items?.map(({ item, price, _id }: IMarketplaceItem, index: number) => (
194
+ {items?.map(({ item, price, _id, acceptedCurrency: listingCurrency }: IMarketplaceItem, index: number) => (
173
195
  <MarketplaceRows
174
196
  key={`${item.key}_${index}`}
175
197
  atlasIMG={atlasIMG}
176
198
  atlasJSON={atlasJSON}
177
199
  item={item}
178
200
  itemPrice={price}
201
+ acceptedCurrency={listingCurrency}
179
202
  equipmentSet={equipmentSet}
180
203
  onMarketPlaceItemRemove={setRemovingItemId.bind(null, _id)}
181
204
  />
@@ -322,12 +345,44 @@ const ItemComponentScrollWrapper = styled.div`
322
345
  const SmallCTAButton = styled(CTAButton)`
323
346
  padding: 8px 12px;
324
347
  height: 32px;
325
-
348
+
326
349
  span {
327
350
  font-size: 0.65rem;
328
351
  }
329
-
352
+
330
353
  svg {
331
354
  font-size: 1.1rem;
332
355
  }
333
356
  `;
357
+
358
+ const CurrencyToggleRow = styled.div`
359
+ display: flex;
360
+ align-items: center;
361
+ gap: 6px;
362
+ margin-top: 8px;
363
+ `;
364
+
365
+ const CurrencyToggleLabel = styled.span`
366
+ font-size: 0.5rem;
367
+ color: #888;
368
+ text-transform: uppercase;
369
+ letter-spacing: 0.5px;
370
+ white-space: nowrap;
371
+ `;
372
+
373
+ const CurrencyToggleButton = styled.button<{ $active: boolean }>`
374
+ padding: 3px 8px;
375
+ font-family: 'Press Start 2P', cursive !important;
376
+ font-size: 0.45rem !important;
377
+ border-radius: 4px;
378
+ border: 1px solid ${({ $active }) => ($active ? '#f59e0b' : 'rgba(255,255,255,0.15)')} !important;
379
+ background: ${({ $active }) => ($active ? 'rgba(245,158,11,0.15)' : 'rgba(0,0,0,0.3)')} !important;
380
+ color: ${({ $active }) => ($active ? '#f59e0b' : '#aaa')} !important;
381
+ cursor: pointer;
382
+ transition: border-color 0.15s, background 0.15s, color 0.15s;
383
+
384
+ &:hover {
385
+ border-color: ${({ $active }) => ($active ? '#f59e0b' : 'rgba(255,255,255,0.35)')} !important;
386
+ color: ${({ $active }) => ($active ? '#f59e0b' : '#ddd')} !important;
387
+ }
388
+ `;
@@ -4,6 +4,7 @@ import {
4
4
  IEquipmentSet,
5
5
  IItem,
6
6
  IMarketplaceItem,
7
+ MarketplaceAcceptedCurrency,
7
8
  } from '@rpg-engine/shared';
8
9
  import { Coins } from 'pixelarticons/react/Coins';
9
10
  import { Delete } from 'pixelarticons/react/Delete';
@@ -26,6 +27,7 @@ export interface IMarketPlaceRowsPropos {
26
27
  item: IItem;
27
28
  itemPrice: number;
28
29
  dcEquivalentPrice?: number;
30
+ acceptedCurrency?: MarketplaceAcceptedCurrency;
29
31
  equipmentSet?: IEquipmentSet | null;
30
32
  scale?: number;
31
33
  onMarketPlaceItemBuy?: () => void;
@@ -40,6 +42,7 @@ export const MarketplaceRows: React.FC<IMarketPlaceRowsPropos> = ({
40
42
  item,
41
43
  itemPrice,
42
44
  dcEquivalentPrice,
45
+ acceptedCurrency,
43
46
  equipmentSet,
44
47
  scale,
45
48
  onMarketPlaceItemBuy,
@@ -93,21 +96,29 @@ export const MarketplaceRows: React.FC<IMarketPlaceRowsPropos> = ({
93
96
  <Ellipsis maxLines={1} maxWidth="200px" fontSize="10px">
94
97
  {item.name}
95
98
  </Ellipsis>
99
+ {acceptedCurrency === MarketplaceAcceptedCurrency.Dc && (
100
+ <CurrencyBadge $color="#a78bfa">DC only</CurrencyBadge>
101
+ )}
102
+ {acceptedCurrency === MarketplaceAcceptedCurrency.Gold && (
103
+ <CurrencyBadge $color="#fef08a">Gold only</CurrencyBadge>
104
+ )}
96
105
  </ItemName>
97
106
  <PriceRow>
98
- <GoldPriceRow>
99
- <GoldIcon>
100
- <SimpleTooltip content="Gold Coin" direction="top">
101
- <SpriteFromAtlas
102
- atlasIMG={atlasIMG}
103
- atlasJSON={atlasJSON}
104
- spriteKey="others/gold-coin-qty-5.png"
105
- imgScale={1}
106
- />
107
- </SimpleTooltip>
108
- </GoldIcon>
109
- <GoldPrice>{itemPrice}</GoldPrice>
110
- </GoldPriceRow>
107
+ {acceptedCurrency !== MarketplaceAcceptedCurrency.Dc && (
108
+ <GoldPriceRow>
109
+ <GoldIcon>
110
+ <SimpleTooltip content="Gold Coin" direction="top">
111
+ <SpriteFromAtlas
112
+ atlasIMG={atlasIMG}
113
+ atlasJSON={atlasJSON}
114
+ spriteKey="others/gold-coin-qty-5.png"
115
+ imgScale={1}
116
+ />
117
+ </SimpleTooltip>
118
+ </GoldIcon>
119
+ <GoldPrice>{itemPrice}</GoldPrice>
120
+ </GoldPriceRow>
121
+ )}
111
122
  {dcEquivalentPrice !== undefined && (
112
123
  <DCPriceRow $clickable={!!onDCCoinClick} onPointerDown={onDCCoinClick}>
113
124
  <DCCoinWrapper>
@@ -169,20 +180,27 @@ export const GroupedMarketplaceRow: React.FC<IGroupedMarketplaceRowProps> = ({
169
180
  onBuy,
170
181
  onDCCoinClick,
171
182
  }) => {
172
- const makeRow = (listing: IMarketplaceItem) => (
173
- <MarketplaceRows
174
- key={listing._id}
175
- atlasIMG={atlasIMG}
176
- atlasJSON={atlasJSON}
177
- item={listing.item}
178
- itemPrice={listing.price}
179
- dcEquivalentPrice={dcToGoldSwapRate > 0 ? getDCEquivalentPrice(listing.price) : undefined}
180
- equipmentSet={equipmentSet}
181
- onMarketPlaceItemBuy={() => onBuy(listing._id)}
182
- onDCCoinClick={onDCCoinClick}
183
- disabled={listing.owner === characterId}
184
- />
185
- );
183
+ const makeRow = (listing: IMarketplaceItem) => {
184
+ const listingCurrency = listing.acceptedCurrency || MarketplaceAcceptedCurrency.GoldOrDc;
185
+ const isDcOnly = listingCurrency === MarketplaceAcceptedCurrency.Dc;
186
+ const showDcPrice = isDcOnly || (dcToGoldSwapRate > 0 && listingCurrency !== MarketplaceAcceptedCurrency.Gold);
187
+
188
+ return (
189
+ <MarketplaceRows
190
+ key={listing._id}
191
+ atlasIMG={atlasIMG}
192
+ atlasJSON={atlasJSON}
193
+ item={listing.item}
194
+ itemPrice={listing.price}
195
+ dcEquivalentPrice={showDcPrice ? getDCEquivalentPrice(listing.price) : undefined}
196
+ acceptedCurrency={listingCurrency}
197
+ equipmentSet={equipmentSet}
198
+ onMarketPlaceItemBuy={() => onBuy(listing._id)}
199
+ onDCCoinClick={isDcOnly ? undefined : onDCCoinClick}
200
+ disabled={listing.owner === characterId}
201
+ />
202
+ );
203
+ };
186
204
 
187
205
  return (
188
206
  <GroupedRowContainer
@@ -303,6 +321,21 @@ const GemContainer = styled.p`
303
321
  font-size: ${uiFonts.size.xsmall} !important;
304
322
  `;
305
323
 
324
+ const CurrencyBadge = styled.span<{ $color: string }>`
325
+ display: inline-block;
326
+ margin-left: 6px;
327
+ padding: 1px 4px;
328
+ font-family: 'Press Start 2P', cursive;
329
+ font-size: 0.38rem;
330
+ color: ${({ $color }) => $color};
331
+ border: 1px solid ${({ $color }) => $color};
332
+ border-radius: 3px;
333
+ opacity: 0.85;
334
+ vertical-align: middle;
335
+ text-transform: uppercase;
336
+ letter-spacing: 0.5px;
337
+ `;
338
+
306
339
  const RarityContainer = styled.div<{ item: IItem }>`
307
340
  border-color: ${({ item }) => rarityColor(item)};
308
341
  box-shadow: ${({ item }) => `0 0 5px 8px ${rarityColor(item)}`} inset,
@@ -12,13 +12,18 @@ export interface IMarketplaceSettingsPanelProps {
12
12
  const CURRENCY_OPTIONS: { value: MarketplaceAcceptedCurrency; label: string; description: string }[] = [
13
13
  {
14
14
  value: MarketplaceAcceptedCurrency.GoldOrDc,
15
- label: 'Gold or DC',
16
- description: 'Accept both Gold and Definya Coin as payment',
15
+ label: 'Both',
16
+ description: 'Gold & DC',
17
17
  },
18
18
  {
19
19
  value: MarketplaceAcceptedCurrency.Gold,
20
- label: 'Gold only',
21
- description: 'Only accept Gold as payment',
20
+ label: 'Gold',
21
+ description: 'Gold only',
22
+ },
23
+ {
24
+ value: MarketplaceAcceptedCurrency.Dc,
25
+ label: 'DC',
26
+ description: 'DC only',
22
27
  },
23
28
  ];
24
29
 
@@ -39,11 +44,10 @@ export const MarketplaceSettingsPanel: React.FC<IMarketplaceSettingsPanelProps>
39
44
  >
40
45
  <OptionLabel $active={acceptedCurrency === option.value}>{option.label}</OptionLabel>
41
46
  <OptionDescription>{option.description}</OptionDescription>
42
- {acceptedCurrency === option.value && <ActiveBadge>Active</ActiveBadge>}
43
47
  </OptionCard>
44
48
  ))}
45
49
  </OptionsGrid>
46
- <Hint>Buyers will only be able to pay using the currency you accept.</Hint>
50
+ <Hint>Default currency for new listings.</Hint>
47
51
  </Section>
48
52
  </Wrapper>
49
53
  );
@@ -72,7 +76,7 @@ const SectionLabel = styled.p`
72
76
 
73
77
  const OptionsGrid = styled.div`
74
78
  display: grid;
75
- grid-template-columns: 1fr 1fr;
79
+ grid-template-columns: repeat(3, 1fr);
76
80
  gap: 12px;
77
81
  `;
78
82
 
@@ -80,45 +84,36 @@ const OptionCard = styled.button<{ $active: boolean }>`
80
84
  position: relative;
81
85
  display: flex;
82
86
  flex-direction: column;
83
- align-items: flex-start;
84
- gap: 6px;
85
- padding: 14px 16px;
86
- background: ${({ $active }) => ($active ? 'rgba(245, 158, 11, 0.12)' : 'rgba(0, 0, 0, 0.25)')};
87
- border: 2px solid ${({ $active }) => ($active ? '#f59e0b' : 'rgba(255,255,255,0.08)')};
87
+ align-items: center;
88
+ justify-content: center;
89
+ gap: 3px;
90
+ padding: 10px 8px;
91
+ background: ${({ $active }) => ($active ? 'rgba(245, 158, 11, 0.12)' : 'rgba(0, 0, 0, 0.25)')} !important;
92
+ border: 2px solid ${({ $active }) => ($active ? '#f59e0b' : 'rgba(255,255,255,0.08)')} !important;
88
93
  border-radius: 6px;
89
94
  cursor: pointer;
90
- text-align: left;
95
+ text-align: center;
91
96
  transition: border-color 0.15s, background 0.15s;
92
97
 
93
98
  &:hover {
94
- border-color: ${({ $active }) => ($active ? '#f59e0b' : 'rgba(255,255,255,0.25)')};
95
- background: ${({ $active }) => ($active ? 'rgba(245, 158, 11, 0.15)' : 'rgba(255,255,255,0.04)')};
99
+ border-color: ${({ $active }) => ($active ? '#f59e0b' : 'rgba(255,255,255,0.25)')} !important;
100
+ background: ${({ $active }) => ($active ? 'rgba(245, 158, 11, 0.15)' : 'rgba(255,255,255,0.04)')} !important;
96
101
  }
97
102
  `;
98
103
 
99
104
  const OptionLabel = styled.span<{ $active: boolean }>`
100
- font-family: 'Press Start 2P', cursive;
101
- font-size: 0.6rem;
102
- color: ${({ $active }) => ($active ? '#f59e0b' : '#cccccc')};
105
+ font-family: 'Press Start 2P', cursive !important;
106
+ font-size: 0.55rem !important;
107
+ color: ${({ $active }) => ($active ? '#f59e0b' : '#999')} !important;
103
108
  letter-spacing: 0.5px;
104
109
  `;
105
110
 
106
111
  const OptionDescription = styled.span`
107
- font-size: 0.5rem;
108
- color: #888;
109
- line-height: 1.5;
112
+ font-size: 0.45rem !important;
113
+ color: #555 !important;
114
+ line-height: 1.4;
110
115
  `;
111
116
 
112
- const ActiveBadge = styled.span`
113
- position: absolute;
114
- top: 8px;
115
- right: 10px;
116
- font-size: 0.45rem;
117
- color: #f59e0b;
118
- text-transform: uppercase;
119
- letter-spacing: 0.5px;
120
- opacity: 0.8;
121
- `;
122
117
 
123
118
  const Hint = styled.p`
124
119
  margin: 14px 0 0 0;
@@ -1,7 +1,9 @@
1
1
  import {
2
2
  IMarketplaceBlueprintSummary,
3
3
  IMarketplaceBuyOrderItem,
4
+ IMarketplaceItem,
4
5
  IMarketplaceTransaction,
6
+ MarketplaceAcceptedCurrency,
5
7
  MarketplaceBuyOrderStatus,
6
8
  MarketplaceTransactionType,
7
9
  } from '@rpg-engine/shared';
@@ -80,6 +82,20 @@ const mockTransactions: IMarketplaceTransaction[] = [
80
82
  { owner: 'player-1', type: MarketplaceTransactionType.BuyOrderCancelled, goldAmount: 300, itemKey: 'items/leather-armor', itemName: 'Leather Armor', createdAt: daysAgo(10), updatedAt: daysAgo(10) },
81
83
  ];
82
84
 
85
+ const dcOnlyItem: IMarketplaceItem = {
86
+ _id: 'dc-only-listing-1',
87
+ owner: 'player-99',
88
+ price: 5000,
89
+ acceptedCurrency: MarketplaceAcceptedCurrency.Dc,
90
+ item: {
91
+ ...items[0],
92
+ _id: 'dc-item-short-sword',
93
+ key: 'short-sword-dc-exclusive',
94
+ name: 'Voidwalker Blade',
95
+ rarity: 'Rare',
96
+ },
97
+ };
98
+
83
99
  const Template: Story = () => {
84
100
  const [page, setPage] = React.useState(1);
85
101
  const [openBuyOrdersPage, setOpenBuyOrdersPage] = React.useState(1);
@@ -129,12 +145,15 @@ const Template: Story = () => {
129
145
  atlasIMG={atlasIMG}
130
146
  atlasJSON={atlasJSON}
131
147
  onClose={() => console.log('close')}
132
- items={items.map(item => ({
133
- item,
134
- price: Math.round(Math.random() * 1000),
135
- _id: Math.random().toString(),
136
- owner: Math.random().toString(),
137
- }))}
148
+ items={[
149
+ ...items.map(item => ({
150
+ item,
151
+ price: Math.round(Math.random() * 1000),
152
+ _id: Math.random().toString(),
153
+ owner: Math.random().toString(),
154
+ })),
155
+ dcOnlyItem,
156
+ ]}
138
157
  equipmentSet={equipmentSetMock}
139
158
  onMarketPlaceItemBuy={tradeId => console.log(tradeId)}
140
159
  onDCCoinClick={() => console.log('open store: packs tab')}
@@ -1,3 +1,4 @@
1
+ import { MarketplaceAcceptedCurrency, goldToDC } from '@rpg-engine/shared';
1
2
  import { Meta, Story } from '@storybook/react';
2
3
  import React from 'react';
3
4
  import { RPGUIRoot } from '../../..';
@@ -36,3 +37,17 @@ export const HighStackQuantity: Story = () => (
36
37
  />
37
38
  </RPGUIRoot>
38
39
  );
40
+
41
+ export const DCOnly: Story = () => (
42
+ <RPGUIRoot>
43
+ <MarketplaceRows
44
+ atlasIMG={atlasIMG}
45
+ atlasJSON={atlasJSON}
46
+ itemPrice={5000}
47
+ item={items[1]}
48
+ acceptedCurrency={MarketplaceAcceptedCurrency.Dc}
49
+ dcEquivalentPrice={goldToDC(5000)}
50
+ onMarketPlaceItemBuy={() => {}}
51
+ />
52
+ </RPGUIRoot>
53
+ );