@rpg-engine/long-bow 0.8.141 → 0.8.146

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.
Files changed (64) hide show
  1. package/dist/components/Marketplace/BlueprintSearchModal.d.ts +17 -0
  2. package/dist/components/Marketplace/BlueprintTable.d.ts +9 -0
  3. package/dist/components/Marketplace/BuyOrderDetailsModal.d.ts +17 -0
  4. package/dist/components/Marketplace/BuyOrderPanel.d.ts +24 -0
  5. package/dist/components/Marketplace/BuyOrderRows.d.ts +13 -0
  6. package/dist/components/Marketplace/BuyPanel.d.ts +9 -1
  7. package/dist/components/Marketplace/HistoryPanel.d.ts +18 -0
  8. package/dist/components/Marketplace/ManagmentPanel.d.ts +3 -2
  9. package/dist/components/Marketplace/Marketplace.d.ts +35 -2
  10. package/dist/components/Marketplace/MarketplaceSettingsPanel.d.ts +2 -1
  11. package/dist/components/Store/PaymentMethodModal.d.ts +1 -0
  12. package/dist/components/shared/LabelPill/LabelPill.d.ts +9 -0
  13. package/dist/components/shared/LabelPill/index.d.ts +1 -0
  14. package/dist/components/shared/SegmentedToggle/SegmentedToggle.d.ts +12 -0
  15. package/dist/components/shared/SegmentedToggle/index.d.ts +1 -0
  16. package/dist/index.d.ts +4 -0
  17. package/dist/long-bow.cjs.development.js +11573 -1288
  18. package/dist/long-bow.cjs.development.js.map +1 -1
  19. package/dist/long-bow.cjs.production.min.js +1 -1
  20. package/dist/long-bow.cjs.production.min.js.map +1 -1
  21. package/dist/long-bow.esm.js +11562 -1290
  22. package/dist/long-bow.esm.js.map +1 -1
  23. package/dist/stories/Features/marketplace/BlueprintSearchModal.stories.d.ts +1 -0
  24. package/dist/stories/Features/marketplace/BuyOrderPanel.stories.d.ts +1 -0
  25. package/dist/stories/Features/marketplace/BuyOrderRows.stories.d.ts +1 -0
  26. package/dist/stories/Features/marketplace/HistoryPanel.stories.d.ts +1 -0
  27. package/dist/stories/Features/trading/MarketplaceRows.stories.d.ts +2 -1
  28. package/dist/stories/UI/buttonsAndInputs/SegmentedToggle.stories.d.ts +6 -0
  29. package/dist/stories/UI/text/LabelPill.stories.d.ts +7 -0
  30. package/dist/utils/atlasUtils.d.ts +2 -0
  31. package/package.json +2 -2
  32. package/src/components/Marketplace/BlueprintSearchModal.tsx +295 -0
  33. package/src/components/Marketplace/BlueprintTable.tsx +158 -0
  34. package/src/components/Marketplace/BuyOrderDetailsModal.tsx +306 -0
  35. package/src/components/Marketplace/BuyOrderPanel.tsx +284 -0
  36. package/src/components/Marketplace/BuyOrderRows.tsx +287 -0
  37. package/src/components/Marketplace/BuyPanel.tsx +406 -166
  38. package/src/components/Marketplace/HistoryPanel.tsx +422 -0
  39. package/src/components/Marketplace/ManagmentPanel.tsx +13 -15
  40. package/src/components/Marketplace/Marketplace.tsx +181 -30
  41. package/src/components/Marketplace/MarketplaceBuyModal.tsx +1 -0
  42. package/src/components/Marketplace/MarketplaceRows.tsx +41 -10
  43. package/src/components/Marketplace/MarketplaceSettingsPanel.tsx +4 -3
  44. package/src/components/Store/CartView.tsx +11 -0
  45. package/src/components/Store/PaymentMethodModal.tsx +26 -9
  46. package/src/components/shared/LabelPill/LabelPill.tsx +45 -0
  47. package/src/components/shared/LabelPill/index.ts +1 -0
  48. package/src/components/shared/SegmentedToggle/SegmentedToggle.tsx +61 -0
  49. package/src/components/shared/SegmentedToggle/index.ts +1 -0
  50. package/src/components/shared/SpriteFromAtlas.tsx +7 -2
  51. package/src/index.tsx +4 -0
  52. package/src/mocks/atlas/items/items.json +33998 -25238
  53. package/src/mocks/atlas/items/items.png +0 -0
  54. package/src/mocks/itemContainer.mocks.ts +31 -0
  55. package/src/stories/Features/marketplace/BlueprintSearchModal.stories.tsx +145 -0
  56. package/src/stories/Features/marketplace/BuyOrderPanel.stories.tsx +323 -0
  57. package/src/stories/Features/marketplace/BuyOrderRows.stories.tsx +116 -0
  58. package/src/stories/Features/marketplace/HistoryPanel.stories.tsx +157 -0
  59. package/src/stories/Features/trading/Marketplace.stories.tsx +130 -0
  60. package/src/stories/Features/trading/MarketplaceRows.stories.tsx +11 -0
  61. package/src/stories/UI/buttonsAndInputs/SegmentedToggle.stories.tsx +54 -0
  62. package/src/stories/UI/text/LabelPill.stories.tsx +43 -0
  63. package/src/utils/__test__/atlasUtils.spec.ts +26 -0
  64. package/src/utils/atlasUtils.ts +80 -0
@@ -0,0 +1,306 @@
1
+ import {
2
+ IMarketplaceBlueprintSummary,
3
+ } from '@rpg-engine/shared';
4
+ import { ShoppingCart } from 'pixelarticons/react/ShoppingCart';
5
+ import React from 'react';
6
+ import { FaTimes } from 'react-icons/fa';
7
+ import styled, { keyframes } from 'styled-components';
8
+ import { Dropdown } from '../Dropdown';
9
+ import { IOptionsProps } from '../Dropdown';
10
+ import { Input } from '../Input';
11
+ import ModalPortal from '../Abstractions/ModalPortal';
12
+ import { CTAButton } from '../shared/CTAButton/CTAButton';
13
+ import { SpriteFromAtlas } from '../shared/SpriteFromAtlas';
14
+
15
+ export interface IBuyOrderDetailsModalProps {
16
+ isOpen: boolean;
17
+ onClose: () => void;
18
+ blueprint: IMarketplaceBlueprintSummary | null;
19
+ quantity: number;
20
+ maxPrice: number;
21
+ rarity: string;
22
+ onQuantityChange: (quantity: number) => void;
23
+ onMaxPriceChange: (price: number) => void;
24
+ onRarityChange: (rarity: string) => void;
25
+ onConfirm: () => void;
26
+ atlasJSON: any;
27
+ atlasIMG: any;
28
+ }
29
+
30
+ const scaleIn = keyframes`
31
+ from { transform: scale(0.85); opacity: 0; }
32
+ to { transform: scale(1); opacity: 1; }
33
+ `;
34
+
35
+ const rarityOptions: IOptionsProps[] = [
36
+ { id: 1, value: 'Common', option: 'Common' },
37
+ { id: 2, value: 'Uncommon', option: 'Uncommon' },
38
+ { id: 3, value: 'Rare', option: 'Rare' },
39
+ { id: 4, value: 'Epic', option: 'Epic' },
40
+ { id: 5, value: 'Legendary', option: 'Legendary' },
41
+ ];
42
+
43
+ export const BuyOrderDetailsModal: React.FC<IBuyOrderDetailsModalProps> = ({
44
+ isOpen,
45
+ onClose,
46
+ blueprint,
47
+ quantity,
48
+ maxPrice,
49
+ rarity,
50
+ onQuantityChange,
51
+ onMaxPriceChange,
52
+ onRarityChange,
53
+ onConfirm,
54
+ atlasJSON,
55
+ atlasIMG,
56
+ }) => {
57
+ if (!isOpen || !blueprint) return null;
58
+
59
+ const stopPropagation = (e: React.MouseEvent | React.PointerEvent): void => {
60
+ e.stopPropagation();
61
+ };
62
+
63
+ const handleClose = (e: React.PointerEvent | React.MouseEvent): void => {
64
+ e.preventDefault();
65
+ e.stopPropagation();
66
+ onClose();
67
+ };
68
+
69
+ return (
70
+ <ModalPortal>
71
+ <Overlay onPointerDown={handleClose} />
72
+ <ModalContainer>
73
+ <ModalContent
74
+ onClick={stopPropagation as React.MouseEventHandler}
75
+ onPointerDown={stopPropagation as React.PointerEventHandler}
76
+ >
77
+ <Header>
78
+ <Title>Place Buy Request</Title>
79
+ <CloseButton onPointerDown={handleClose} aria-label="Close">
80
+ <FaTimes />
81
+ </CloseButton>
82
+ </Header>
83
+
84
+ <ItemDisplay>
85
+ <SpriteWrapper>
86
+ <SpriteFromAtlas
87
+ atlasJSON={atlasJSON}
88
+ atlasIMG={atlasIMG}
89
+ spriteKey={blueprint.texturePath || blueprint.key}
90
+ width={32}
91
+ height={32}
92
+ imgScale={2}
93
+ />
94
+ </SpriteWrapper>
95
+ <ItemInfo>
96
+ <ItemName>{blueprint.name}</ItemName>
97
+ <ItemMeta>{[blueprint.type, blueprint.subType].filter(Boolean).filter((v, i, arr) => arr.indexOf(v) === i).join(' · ')} · T{blueprint.tier}</ItemMeta>
98
+ </ItemInfo>
99
+ </ItemDisplay>
100
+
101
+ <FormSection>
102
+ <FieldRow>
103
+ <Label>Quantity</Label>
104
+ <StyledInput
105
+ value={quantity || ''}
106
+ onChange={(e) => onQuantityChange(Number(e.target.value))}
107
+ placeholder="Qty"
108
+ type="number"
109
+ min={1}
110
+ />
111
+ </FieldRow>
112
+
113
+ <FieldRow>
114
+ <Label>Max Gold</Label>
115
+ <StyledInput
116
+ value={maxPrice || ''}
117
+ onChange={(e) => onMaxPriceChange(Number(e.target.value))}
118
+ placeholder="Max gold"
119
+ type="number"
120
+ min={1}
121
+ />
122
+ </FieldRow>
123
+
124
+ <FieldRow>
125
+ <Label>Rarity</Label>
126
+ <StyledDropdown
127
+ key={rarity}
128
+ options={rarityOptions}
129
+ onChange={onRarityChange}
130
+ width="100%"
131
+ />
132
+ </FieldRow>
133
+ </FormSection>
134
+
135
+ <ActionsRow>
136
+ <CancelButton onPointerDown={handleClose}>Cancel</CancelButton>
137
+ <CTAButton
138
+ icon={<ShoppingCart width={16} height={16} />}
139
+ label="Place Request"
140
+ disabled={quantity <= 0 || maxPrice <= 0}
141
+ onClick={onConfirm}
142
+ />
143
+ </ActionsRow>
144
+ </ModalContent>
145
+ </ModalContainer>
146
+ </ModalPortal>
147
+ );
148
+ };
149
+
150
+ const Overlay = styled.div`
151
+ position: fixed;
152
+ inset: 0;
153
+ background: rgba(0, 0, 0, 0.7);
154
+ z-index: 1000;
155
+ `;
156
+
157
+ const ModalContainer = styled.div`
158
+ position: fixed;
159
+ inset: 0;
160
+ display: flex;
161
+ align-items: center;
162
+ justify-content: center;
163
+ z-index: 1001;
164
+ pointer-events: none;
165
+ `;
166
+
167
+ const ModalContent = styled.div`
168
+ background: #1a1a2e;
169
+ border: 2px solid #f59e0b;
170
+ border-radius: 8px;
171
+ padding: 20px 24px;
172
+ width: 400px;
173
+ max-width: 90%;
174
+ display: flex;
175
+ flex-direction: column;
176
+ gap: 16px;
177
+ pointer-events: auto;
178
+ animation: ${scaleIn} 0.15s ease-out;
179
+ `;
180
+
181
+ const Header = styled.div`
182
+ display: flex;
183
+ align-items: center;
184
+ justify-content: space-between;
185
+ `;
186
+
187
+ const Title = styled.h3`
188
+ margin: 0;
189
+ font-family: 'Press Start 2P', cursive;
190
+ font-size: 0.7rem;
191
+ color: #fef08a;
192
+ `;
193
+
194
+ const CloseButton = styled.button`
195
+ background: none;
196
+ border: none;
197
+ color: rgba(255, 255, 255, 0.6);
198
+ cursor: pointer;
199
+ font-size: 1rem;
200
+ padding: 4px;
201
+ display: flex;
202
+ align-items: center;
203
+ pointer-events: auto;
204
+
205
+ &:hover {
206
+ color: #ffffff;
207
+ }
208
+ `;
209
+
210
+ const ItemDisplay = styled.div`
211
+ display: flex;
212
+ align-items: center;
213
+ gap: 12px;
214
+ padding: 12px;
215
+ background: rgba(0, 0, 0, 0.2);
216
+ border: 1px solid rgba(255, 255, 255, 0.05);
217
+ border-radius: 4px;
218
+ `;
219
+
220
+ const SpriteWrapper = styled.div`
221
+ display: flex;
222
+ align-items: center;
223
+ justify-content: center;
224
+ `;
225
+
226
+ const ItemInfo = styled.div`
227
+ display: flex;
228
+ flex-direction: column;
229
+ gap: 2px;
230
+ overflow: hidden;
231
+ `;
232
+
233
+ const ItemName = styled.span`
234
+ font-size: 0.55rem;
235
+ color: #ddd;
236
+ overflow: hidden;
237
+ text-overflow: ellipsis;
238
+ white-space: nowrap;
239
+ `;
240
+
241
+ const ItemMeta = styled.span`
242
+ font-size: 0.4rem;
243
+ color: #666;
244
+ overflow: hidden;
245
+ text-overflow: ellipsis;
246
+ white-space: nowrap;
247
+ `;
248
+
249
+ const FormSection = styled.div`
250
+ display: flex;
251
+ flex-direction: column;
252
+ gap: 12px;
253
+ `;
254
+
255
+ const FieldRow = styled.div`
256
+ display: flex;
257
+ flex-direction: column;
258
+ gap: 6px;
259
+
260
+ .rpgui-content .rpgui-dropdown-imp-header {
261
+ padding: 0px 10px 0 !important;
262
+ }
263
+ `;
264
+
265
+ const Label = styled.label`
266
+ font-size: 0.5rem;
267
+ color: #aaa;
268
+ text-transform: uppercase;
269
+ letter-spacing: 0.5px;
270
+ `;
271
+
272
+ const StyledInput = styled(Input)`
273
+ width: 100%;
274
+ `;
275
+
276
+ const StyledDropdown = styled(Dropdown)`
277
+ margin: 0px !important;
278
+ width: 100% !important;
279
+ `;
280
+
281
+ const ActionsRow = styled.div`
282
+ display: flex;
283
+ gap: 8px;
284
+ margin-top: 4px;
285
+ `;
286
+
287
+ const CancelButton = styled.button`
288
+ flex: 1;
289
+ background: rgba(255, 255, 255, 0.05);
290
+ border: 1px solid rgba(255, 255, 255, 0.1);
291
+ color: #ccc;
292
+ border-radius: 4px;
293
+ padding: 8px 12px;
294
+ font-size: 0.5rem;
295
+ font-family: 'Press Start 2P', cursive;
296
+ cursor: pointer;
297
+ text-transform: uppercase;
298
+ letter-spacing: 0.5px;
299
+ transition: background 0.1s, border-color 0.1s;
300
+ pointer-events: auto;
301
+
302
+ &:hover {
303
+ background: rgba(255, 255, 255, 0.08);
304
+ border-color: rgba(255, 255, 255, 0.15);
305
+ }
306
+ `;
@@ -0,0 +1,284 @@
1
+ import {
2
+ IMarketplaceBlueprintSummary,
3
+ IMarketplaceBuyOrderItem,
4
+ } from '@rpg-engine/shared';
5
+ import { Search } from 'pixelarticons/react/Search';
6
+ import React, { useEffect, useState } from 'react';
7
+ import styled from 'styled-components';
8
+ import { Pager } from '../Pager';
9
+ import { CTAButton } from '../shared/CTAButton/CTAButton';
10
+ import { rarityColor } from '../Item/Inventory/ItemSlotRarity';
11
+ import { SpriteFromAtlas } from '../shared/SpriteFromAtlas';
12
+ import { BuyOrderDetailsModal } from './BuyOrderDetailsModal';
13
+ import { BuyOrderRow } from './BuyOrderRows';
14
+
15
+ export interface IBuyOrderPanelProps {
16
+ atlasJSON?: any;
17
+ atlasIMG?: any;
18
+ selectedBlueprint?: IMarketplaceBlueprintSummary;
19
+ onOpenBlueprintSearch: () => void;
20
+ onCloseDetails?: () => void;
21
+ onQuantityChange: (quantity: number) => void;
22
+ onMaxPriceChange: (price: number) => void;
23
+ onRarityChange: (rarity: string) => void;
24
+ onPlaceBuyOrder: () => void;
25
+ currentQuantity: number;
26
+ currentMaxPrice: number;
27
+ selectedRarity: string;
28
+
29
+ yourBuyOrders: IMarketplaceBuyOrderItem[];
30
+ yourBuyOrdersTotal: number;
31
+ yourBuyOrdersPage: number;
32
+ onYourBuyOrdersPageChange: (page: number) => void;
33
+ onCancelBuyOrder: (buyOrderId: string) => void;
34
+ }
35
+
36
+ const BUY_ORDERS_PER_PAGE = 5;
37
+
38
+ export const BuyOrderPanel: React.FC<IBuyOrderPanelProps> = (props) => {
39
+ const {
40
+ atlasJSON,
41
+ atlasIMG,
42
+ selectedBlueprint,
43
+ onOpenBlueprintSearch,
44
+ onCloseDetails,
45
+ onQuantityChange,
46
+ onMaxPriceChange,
47
+ onRarityChange,
48
+ onPlaceBuyOrder,
49
+ currentQuantity,
50
+ currentMaxPrice,
51
+ selectedRarity,
52
+ yourBuyOrders,
53
+ yourBuyOrdersTotal,
54
+ yourBuyOrdersPage,
55
+ onYourBuyOrdersPageChange,
56
+ onCancelBuyOrder,
57
+ } = props;
58
+
59
+ // Local blueprint display: cleared immediately on Place Request so the
60
+ // panel returns to "Select Item" without waiting for the consumer to update
61
+ // the prop. Cancel keeps it shown so the user can reopen the modal.
62
+ const [displayedBlueprint, setDisplayedBlueprint] = useState(selectedBlueprint);
63
+ const [isDetailsOpen, setIsDetailsOpen] = useState(!!selectedBlueprint);
64
+
65
+ // Sync when consumer provides a new blueprint (e.g. after search selection)
66
+ useEffect(() => {
67
+ if (selectedBlueprint) {
68
+ setDisplayedBlueprint(selectedBlueprint);
69
+ setIsDetailsOpen(true);
70
+ }
71
+ }, [selectedBlueprint]);
72
+
73
+ // Place request: clear display + close modal, then notify consumer
74
+ const handleConfirm = () => {
75
+ onPlaceBuyOrder();
76
+ setDisplayedBlueprint(undefined);
77
+ setIsDetailsOpen(false);
78
+ onCloseDetails?.();
79
+ };
80
+
81
+ // Cancel: just close the modal, keep blueprint displayed for reopening
82
+ const handleCloseDetails = () => {
83
+ setIsDetailsOpen(false);
84
+ };
85
+
86
+ return (
87
+ <PanelWrapper>
88
+ {/* ── Details modal ── */}
89
+ {displayedBlueprint && isDetailsOpen && (
90
+ <BuyOrderDetailsModal
91
+ isOpen
92
+ onClose={handleCloseDetails}
93
+ blueprint={displayedBlueprint}
94
+ quantity={currentQuantity}
95
+ maxPrice={currentMaxPrice}
96
+ rarity={selectedRarity}
97
+ onQuantityChange={onQuantityChange}
98
+ onMaxPriceChange={onMaxPriceChange}
99
+ onRarityChange={onRarityChange}
100
+ onConfirm={handleConfirm}
101
+ atlasJSON={atlasJSON}
102
+ atlasIMG={atlasIMG}
103
+ />
104
+ )}
105
+
106
+ {/* ── Form row — outside scroll so dropdown isn't clipped ── */}
107
+ <FormRow>
108
+ {displayedBlueprint ? (
109
+ <SelectedBlueprintDisplay onPointerDown={onOpenBlueprintSearch}>
110
+ <RarityContainer $rarity={selectedRarity}>
111
+ <SpriteFromAtlas
112
+ atlasIMG={atlasIMG}
113
+ atlasJSON={atlasJSON}
114
+ spriteKey={displayedBlueprint.texturePath || displayedBlueprint.key}
115
+ width={32}
116
+ height={32}
117
+ imgScale={2}
118
+ centered
119
+ />
120
+ </RarityContainer>
121
+ <ChangeTextWrapper>
122
+ <BlueprintName>{displayedBlueprint.name}</BlueprintName>
123
+ <ChangeText>change</ChangeText>
124
+ </ChangeTextWrapper>
125
+ </SelectedBlueprintDisplay>
126
+ ) : (
127
+ <CTAButton
128
+ icon={<Search width={18} height={18} />}
129
+ label="Select Item"
130
+ iconColor="#f59e0b"
131
+ onClick={onOpenBlueprintSearch}
132
+ />
133
+ )}
134
+ </FormRow>
135
+
136
+ {/* ── Scrollable lists ──────────────────────────────── */}
137
+ <ScrollArea id="MarketContainer">
138
+ <Section>
139
+ <SectionTitle>Your Buy Requests</SectionTitle>
140
+ {yourBuyOrders.length === 0 ? (
141
+ <EmptyState>No requests yet</EmptyState>
142
+ ) : (
143
+ yourBuyOrders.map((order) => (
144
+ <BuyOrderRow
145
+ key={order._id}
146
+ buyOrder={order}
147
+ atlasJSON={atlasJSON}
148
+ atlasIMG={atlasIMG}
149
+ isOwn
150
+ onCancel={onCancelBuyOrder}
151
+ />
152
+ ))
153
+ )}
154
+ {yourBuyOrdersTotal > BUY_ORDERS_PER_PAGE && (
155
+ <PagerRow>
156
+ <Pager
157
+ totalItems={yourBuyOrdersTotal}
158
+ currentPage={yourBuyOrdersPage}
159
+ itemsPerPage={BUY_ORDERS_PER_PAGE}
160
+ onPageChange={onYourBuyOrdersPageChange}
161
+ />
162
+ </PagerRow>
163
+ )}
164
+ </Section>
165
+
166
+ </ScrollArea>
167
+ </PanelWrapper>
168
+ );
169
+ };
170
+
171
+ const PanelWrapper = styled.div`
172
+ display: flex;
173
+ flex-direction: column;
174
+ gap: 8px;
175
+ padding: 0 2.5%;
176
+ width: 100%;
177
+ box-sizing: border-box;
178
+ `;
179
+
180
+ const FormRow = styled.div`
181
+ display: flex;
182
+ gap: 8px;
183
+ align-items: center;
184
+ background: rgba(0, 0, 0, 0.15);
185
+ border-radius: 4px;
186
+ border: 1px solid rgba(255, 255, 255, 0.05);
187
+ padding: 8px 12px;
188
+ overflow: visible;
189
+ `;
190
+
191
+ const ScrollArea = styled.div`
192
+ display: flex;
193
+ flex-direction: column;
194
+ gap: 6px;
195
+ overflow-y: scroll;
196
+ max-height: 420px;
197
+ `;
198
+
199
+ const Section = styled.div`
200
+ display: flex;
201
+ flex-direction: column;
202
+ gap: 2px;
203
+ `;
204
+
205
+ const SectionTitle = styled.p`
206
+ margin: 0 0 2px 0;
207
+ font-size: 0.45rem;
208
+ color: #666;
209
+ text-transform: uppercase;
210
+ letter-spacing: 1px;
211
+ `;
212
+
213
+ const SelectedBlueprintDisplay = styled.button`
214
+ background: rgba(245, 158, 11, 0.08);
215
+ border: 1px solid rgba(245, 158, 11, 0.4);
216
+ border-radius: 4px;
217
+ padding: 6px 10px;
218
+ cursor: pointer;
219
+ text-align: left;
220
+ display: flex;
221
+ align-items: center;
222
+ gap: 8px;
223
+ transition: background 0.1s;
224
+
225
+ /* Adjust sprite position slightly down and right */
226
+ > div:first-child {
227
+ position: relative;
228
+ top: 2px;
229
+ left: 2px;
230
+ }
231
+
232
+ &:hover {
233
+ background: rgba(245, 158, 11, 0.15);
234
+ }
235
+ `;
236
+
237
+ const RarityContainer = styled.div<{ $rarity: string }>`
238
+ border-color: ${({ $rarity }) => rarityColor({ rarity: $rarity } as any)};
239
+ box-shadow: ${({ $rarity }) => `0 0 5px 8px ${rarityColor({ rarity: $rarity } as any)}`} inset,
240
+ ${({ $rarity }) => `0 0 8px 6px ${rarityColor({ rarity: $rarity } as any)}`};
241
+ width: 32px;
242
+ height: 32px;
243
+ `;
244
+
245
+ const ChangeTextWrapper = styled.div`
246
+ display: flex;
247
+ flex-direction: column;
248
+ gap: 2px;
249
+ min-width: 0;
250
+ `;
251
+
252
+ const BlueprintName = styled.span`
253
+ font-size: 0.5rem;
254
+ color: #ddd;
255
+ white-space: nowrap;
256
+ overflow: hidden;
257
+ text-overflow: ellipsis;
258
+ `;
259
+
260
+ const ChangeText = styled.span`
261
+ font-size: 0.4rem;
262
+ color: #f59e0b;
263
+ `;
264
+
265
+ const EmptyState = styled.div`
266
+ display: flex;
267
+ align-items: center;
268
+ justify-content: center;
269
+ height: 45px;
270
+ font-size: 0.45rem;
271
+ color: #555;
272
+ text-transform: uppercase;
273
+ letter-spacing: 1px;
274
+ background: rgba(0, 0, 0, 0.15);
275
+ border-radius: 4px;
276
+ `;
277
+
278
+ const PagerRow = styled.div`
279
+ display: flex;
280
+ justify-content: center;
281
+ margin-top: 4px;
282
+ `;
283
+
284
+ export { BUY_ORDERS_PER_PAGE };