@rpg-engine/long-bow 0.8.145 → 0.8.148
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/BlueprintSearchModal.d.ts +2 -0
- package/dist/components/Marketplace/BlueprintTable.d.ts +9 -0
- package/dist/components/Marketplace/BuyOrderDetailsModal.d.ts +2 -0
- package/dist/components/Marketplace/BuyOrderPanel.d.ts +2 -0
- package/dist/long-bow.cjs.development.js +280 -151
- 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 +280 -151
- package/dist/long-bow.esm.js.map +1 -1
- package/package.json +2 -2
- package/src/components/Marketplace/BlueprintSearchModal.tsx +77 -146
- package/src/components/Marketplace/BlueprintTable.tsx +158 -0
- package/src/components/Marketplace/BuyOrderDetailsModal.tsx +17 -10
- package/src/components/Marketplace/BuyOrderPanel.tsx +75 -22
- package/src/components/Marketplace/HistoryPanel.tsx +1 -1
- package/src/components/Marketplace/Marketplace.tsx +6 -1
- package/src/stories/Features/marketplace/BuyOrderPanel.stories.tsx +197 -81
- package/src/stories/Features/marketplace/HistoryPanel.stories.tsx +3 -3
- package/src/stories/Features/trading/Marketplace.stories.tsx +30 -7
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.148",
|
|
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": "
|
|
87
|
+
"@rpg-engine/shared": "^0.10.90",
|
|
88
88
|
"dayjs": "^1.11.2",
|
|
89
89
|
"font-awesome": "^4.7.0",
|
|
90
90
|
"fs-extra": "^10.1.0",
|
|
@@ -3,15 +3,16 @@ import {
|
|
|
3
3
|
IMarketplaceBlueprintSummary,
|
|
4
4
|
ItemSubType,
|
|
5
5
|
} from '@rpg-engine/shared';
|
|
6
|
-
import
|
|
6
|
+
import { debounce } from 'lodash';
|
|
7
|
+
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
7
8
|
import { FaTimes } from 'react-icons/fa';
|
|
8
|
-
import styled from 'styled-components';
|
|
9
|
+
import styled, { keyframes } from 'styled-components';
|
|
9
10
|
import { Dropdown } from '../Dropdown';
|
|
10
11
|
import { IOptionsProps } from '../Dropdown';
|
|
11
12
|
import { Input } from '../Input';
|
|
12
13
|
import { Pager } from '../Pager';
|
|
13
14
|
import ModalPortal from '../Abstractions/ModalPortal';
|
|
14
|
-
import {
|
|
15
|
+
import { BlueprintTable } from './BlueprintTable';
|
|
15
16
|
|
|
16
17
|
export interface IBlueprintSearchModalProps {
|
|
17
18
|
isOpen: boolean;
|
|
@@ -24,10 +25,17 @@ export interface IBlueprintSearchModalProps {
|
|
|
24
25
|
isLoading: boolean;
|
|
25
26
|
atlasJSON: any;
|
|
26
27
|
atlasIMG: any;
|
|
28
|
+
enableHotkeys?: () => void;
|
|
29
|
+
disableHotkeys?: () => void;
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
const BLUEPRINTS_PER_PAGE = 10;
|
|
30
33
|
|
|
34
|
+
const scaleIn = keyframes`
|
|
35
|
+
from { transform: scale(0.85); opacity: 0; }
|
|
36
|
+
to { transform: scale(1); opacity: 1; }
|
|
37
|
+
`;
|
|
38
|
+
|
|
31
39
|
const typeOptions: IOptionsProps[] = [
|
|
32
40
|
{ id: 1, value: '', option: 'All Types' },
|
|
33
41
|
...Object.keys(ItemSubType)
|
|
@@ -53,27 +61,49 @@ export const BlueprintSearchModal: React.FC<IBlueprintSearchModalProps> = ({
|
|
|
53
61
|
isLoading,
|
|
54
62
|
atlasJSON,
|
|
55
63
|
atlasIMG,
|
|
64
|
+
enableHotkeys,
|
|
65
|
+
disableHotkeys,
|
|
56
66
|
}) => {
|
|
57
67
|
const [searchName, setSearchName] = useState('');
|
|
58
68
|
const [selectedType, setSelectedType] = useState('');
|
|
59
69
|
const [selectedSubType, setSelectedSubType] = useState('');
|
|
60
70
|
|
|
61
|
-
|
|
71
|
+
const searchNameRef = useRef(searchName);
|
|
72
|
+
const selectedTypeRef = useRef(selectedType);
|
|
73
|
+
const selectedSubTypeRef = useRef(selectedSubType);
|
|
74
|
+
|
|
75
|
+
searchNameRef.current = searchName;
|
|
76
|
+
selectedTypeRef.current = selectedType;
|
|
77
|
+
selectedSubTypeRef.current = selectedSubType;
|
|
78
|
+
|
|
79
|
+
const triggerSearch = useCallback(
|
|
80
|
+
(overrides?: Partial<{ name: string; itemType: string; itemSubType: string; page: number }>): void => {
|
|
81
|
+
onSearch({
|
|
82
|
+
npcId: '',
|
|
83
|
+
name: overrides?.name ?? searchNameRef.current,
|
|
84
|
+
itemType: overrides?.itemType ?? selectedTypeRef.current,
|
|
85
|
+
itemSubType: overrides?.itemSubType ?? selectedSubTypeRef.current,
|
|
86
|
+
page: overrides?.page ?? 1,
|
|
87
|
+
limit: BLUEPRINTS_PER_PAGE,
|
|
88
|
+
});
|
|
89
|
+
},
|
|
90
|
+
[onSearch]
|
|
91
|
+
);
|
|
62
92
|
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
93
|
+
const debouncedNameSearch = useMemo(
|
|
94
|
+
() => debounce((name: string) => triggerSearch({ name, page: 1 }), 300),
|
|
95
|
+
[triggerSearch]
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
return () => { debouncedNameSearch.cancel(); };
|
|
100
|
+
}, [debouncedNameSearch]);
|
|
101
|
+
|
|
102
|
+
if (!isOpen) return null;
|
|
73
103
|
|
|
74
104
|
const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
|
|
75
105
|
setSearchName(e.target.value);
|
|
76
|
-
|
|
106
|
+
debouncedNameSearch(e.target.value);
|
|
77
107
|
};
|
|
78
108
|
|
|
79
109
|
const handleTypeChange = (value: string): void => {
|
|
@@ -121,6 +151,8 @@ export const BlueprintSearchModal: React.FC<IBlueprintSearchModalProps> = ({
|
|
|
121
151
|
value={searchName}
|
|
122
152
|
onChange={handleNameChange}
|
|
123
153
|
placeholder="Search by name..."
|
|
154
|
+
onFocus={disableHotkeys}
|
|
155
|
+
onBlur={enableHotkeys}
|
|
124
156
|
/>
|
|
125
157
|
</InputWrapper>
|
|
126
158
|
|
|
@@ -140,47 +172,22 @@ export const BlueprintSearchModal: React.FC<IBlueprintSearchModalProps> = ({
|
|
|
140
172
|
</FiltersRow>
|
|
141
173
|
|
|
142
174
|
<ResultsWrapper>
|
|
143
|
-
{isLoading ? (
|
|
144
|
-
<EmptyState>
|
|
145
|
-
) : blueprints.length === 0 ? (
|
|
146
|
-
<EmptyState>No blueprints found</EmptyState>
|
|
175
|
+
{blueprints.length === 0 && !isLoading ? (
|
|
176
|
+
<EmptyState>No items found</EmptyState>
|
|
147
177
|
) : (
|
|
148
|
-
|
|
149
|
-
<
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
atlasJSON={atlasJSON}
|
|
162
|
-
atlasIMG={atlasIMG}
|
|
163
|
-
spriteKey={blueprint.texturePath || blueprint.key}
|
|
164
|
-
width={32}
|
|
165
|
-
height={32}
|
|
166
|
-
imgScale={2}
|
|
167
|
-
centered
|
|
168
|
-
/>
|
|
169
|
-
</SpriteWrapper>
|
|
170
|
-
<ColName>
|
|
171
|
-
<BlueprintName>{blueprint.name}</BlueprintName>
|
|
172
|
-
<BlueprintKey>{blueprint.key}</BlueprintKey>
|
|
173
|
-
</ColName>
|
|
174
|
-
<ColType>
|
|
175
|
-
<TypeText>{blueprint.type}</TypeText>
|
|
176
|
-
{blueprint.subType && blueprint.subType !== blueprint.type && (
|
|
177
|
-
<SubTypeText>{blueprint.subType}</SubTypeText>
|
|
178
|
-
)}
|
|
179
|
-
</ColType>
|
|
180
|
-
<ColTier>T{blueprint.tier}</ColTier>
|
|
181
|
-
</ResultRow>
|
|
182
|
-
))}
|
|
183
|
-
</>
|
|
178
|
+
<ResultsContent $dimmed={isLoading}>
|
|
179
|
+
<BlueprintTable
|
|
180
|
+
blueprints={blueprints}
|
|
181
|
+
atlasJSON={atlasJSON}
|
|
182
|
+
atlasIMG={atlasIMG}
|
|
183
|
+
onSelect={onSelect}
|
|
184
|
+
/>
|
|
185
|
+
</ResultsContent>
|
|
186
|
+
)}
|
|
187
|
+
{isLoading && (
|
|
188
|
+
<LoadingOverlay>
|
|
189
|
+
<LoadingText>Loading...</LoadingText>
|
|
190
|
+
</LoadingOverlay>
|
|
184
191
|
)}
|
|
185
192
|
</ResultsWrapper>
|
|
186
193
|
|
|
@@ -226,12 +233,7 @@ const ModalContent = styled.div`
|
|
|
226
233
|
flex-direction: column;
|
|
227
234
|
gap: 12px;
|
|
228
235
|
pointer-events: auto;
|
|
229
|
-
animation: scaleIn 0.15s ease-out;
|
|
230
|
-
|
|
231
|
-
@keyframes scaleIn {
|
|
232
|
-
from { transform: scale(0.85); opacity: 0; }
|
|
233
|
-
to { transform: scale(1); opacity: 1; }
|
|
234
|
-
}
|
|
236
|
+
animation: ${scaleIn} 0.15s ease-out;
|
|
235
237
|
`;
|
|
236
238
|
|
|
237
239
|
const Header = styled.div`
|
|
@@ -284,7 +286,6 @@ const InputWrapper = styled.div`
|
|
|
284
286
|
|
|
285
287
|
const StyledInput = styled(Input)`
|
|
286
288
|
flex: 1;
|
|
287
|
-
height: 10px;
|
|
288
289
|
`;
|
|
289
290
|
|
|
290
291
|
const FiltersRow = styled.div`
|
|
@@ -299,110 +300,40 @@ const StyledDropdown = styled(Dropdown)`
|
|
|
299
300
|
`;
|
|
300
301
|
|
|
301
302
|
const ResultsWrapper = styled.div`
|
|
303
|
+
position: relative;
|
|
302
304
|
overflow-y: auto;
|
|
303
|
-
|
|
305
|
+
height: 320px;
|
|
304
306
|
background: rgba(0, 0, 0, 0.2);
|
|
305
307
|
border: 1px solid rgba(255, 255, 255, 0.05);
|
|
306
308
|
border-radius: 4px;
|
|
307
309
|
`;
|
|
308
310
|
|
|
309
|
-
const
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
align-items: center;
|
|
313
|
-
gap: 8px;
|
|
314
|
-
padding: 6px 12px;
|
|
315
|
-
`;
|
|
316
|
-
|
|
317
|
-
const ResultsHeader = styled.div`
|
|
318
|
-
${tableRowBase}
|
|
319
|
-
background: rgba(0, 0, 0, 0.4);
|
|
320
|
-
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
|
321
|
-
position: sticky;
|
|
322
|
-
top: 0;
|
|
323
|
-
z-index: 1;
|
|
324
|
-
|
|
325
|
-
> * {
|
|
326
|
-
font-size: 0.45rem;
|
|
327
|
-
color: #888;
|
|
328
|
-
text-transform: uppercase;
|
|
329
|
-
letter-spacing: 1px;
|
|
330
|
-
}
|
|
311
|
+
const ResultsContent = styled.div<{ $dimmed?: boolean }>`
|
|
312
|
+
opacity: ${(p) => (p.$dimmed ? 0.4 : 1)};
|
|
313
|
+
transition: opacity 0.15s ease;
|
|
331
314
|
`;
|
|
332
315
|
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
cursor: pointer;
|
|
337
|
-
transition: background 0.1s;
|
|
338
|
-
|
|
339
|
-
&:hover {
|
|
340
|
-
background: rgba(245, 158, 11, 0.08);
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
&:last-child {
|
|
344
|
-
border-bottom: none;
|
|
345
|
-
}
|
|
346
|
-
`;
|
|
347
|
-
|
|
348
|
-
const SpriteWrapper = styled.div`
|
|
316
|
+
const LoadingOverlay = styled.div`
|
|
317
|
+
position: absolute;
|
|
318
|
+
inset: 0;
|
|
349
319
|
display: flex;
|
|
350
320
|
align-items: center;
|
|
351
321
|
justify-content: center;
|
|
352
|
-
|
|
353
|
-
height: 32px;
|
|
354
|
-
`;
|
|
355
|
-
|
|
356
|
-
const ColName = styled.div`
|
|
357
|
-
display: flex;
|
|
358
|
-
flex-direction: column;
|
|
359
|
-
gap: 2px;
|
|
360
|
-
overflow: hidden;
|
|
361
|
-
`;
|
|
362
|
-
|
|
363
|
-
const BlueprintName = styled.span`
|
|
364
|
-
font-size: 0.5rem;
|
|
365
|
-
color: #ddd;
|
|
366
|
-
overflow: hidden;
|
|
367
|
-
text-overflow: ellipsis;
|
|
368
|
-
white-space: nowrap;
|
|
369
|
-
`;
|
|
370
|
-
|
|
371
|
-
const BlueprintKey = styled.span`
|
|
372
|
-
font-size: 0.4rem;
|
|
373
|
-
color: #666;
|
|
374
|
-
overflow: hidden;
|
|
375
|
-
text-overflow: ellipsis;
|
|
376
|
-
white-space: nowrap;
|
|
377
|
-
`;
|
|
378
|
-
|
|
379
|
-
const ColType = styled.div`
|
|
380
|
-
display: flex;
|
|
381
|
-
flex-direction: column;
|
|
382
|
-
gap: 2px;
|
|
383
|
-
`;
|
|
384
|
-
|
|
385
|
-
const TypeText = styled.span`
|
|
386
|
-
font-size: 0.45rem;
|
|
387
|
-
color: #aaa;
|
|
388
|
-
`;
|
|
389
|
-
|
|
390
|
-
const SubTypeText = styled.span`
|
|
391
|
-
font-size: 0.4rem;
|
|
392
|
-
color: #666;
|
|
322
|
+
pointer-events: none;
|
|
393
323
|
`;
|
|
394
324
|
|
|
395
|
-
const
|
|
396
|
-
font-size: 0.
|
|
325
|
+
const LoadingText = styled.span`
|
|
326
|
+
font-size: 0.55rem;
|
|
397
327
|
color: #f59e0b;
|
|
398
|
-
text-
|
|
328
|
+
text-transform: uppercase;
|
|
329
|
+
letter-spacing: 1px;
|
|
399
330
|
`;
|
|
400
331
|
|
|
401
332
|
const EmptyState = styled.div`
|
|
402
333
|
display: flex;
|
|
403
334
|
align-items: center;
|
|
404
335
|
justify-content: center;
|
|
405
|
-
height:
|
|
336
|
+
height: 100%;
|
|
406
337
|
font-size: 0.55rem;
|
|
407
338
|
color: #666;
|
|
408
339
|
text-transform: uppercase;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { IMarketplaceBlueprintSummary } from '@rpg-engine/shared';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
import { SpriteFromAtlas } from '../shared/SpriteFromAtlas';
|
|
5
|
+
|
|
6
|
+
export interface IBlueprintTableProps {
|
|
7
|
+
blueprints: IMarketplaceBlueprintSummary[];
|
|
8
|
+
atlasJSON: any;
|
|
9
|
+
atlasIMG: any;
|
|
10
|
+
onSelect?: (blueprint: IMarketplaceBlueprintSummary) => void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const BlueprintTable: React.FC<IBlueprintTableProps> = ({
|
|
14
|
+
blueprints,
|
|
15
|
+
atlasJSON,
|
|
16
|
+
atlasIMG,
|
|
17
|
+
onSelect,
|
|
18
|
+
}) => {
|
|
19
|
+
return (
|
|
20
|
+
<>
|
|
21
|
+
<ResultsHeader>
|
|
22
|
+
<span />
|
|
23
|
+
<ColName>Name</ColName>
|
|
24
|
+
<ColType>Type</ColType>
|
|
25
|
+
<ColTier>Tier</ColTier>
|
|
26
|
+
</ResultsHeader>
|
|
27
|
+
{blueprints.map((blueprint) => (
|
|
28
|
+
<ResultRow
|
|
29
|
+
key={blueprint.key}
|
|
30
|
+
$selectable={!!onSelect}
|
|
31
|
+
onPointerDown={onSelect ? () => onSelect(blueprint) : undefined}
|
|
32
|
+
>
|
|
33
|
+
<SpriteWrapper>
|
|
34
|
+
<SpriteFromAtlas
|
|
35
|
+
atlasJSON={atlasJSON}
|
|
36
|
+
atlasIMG={atlasIMG}
|
|
37
|
+
spriteKey={blueprint.texturePath || blueprint.key}
|
|
38
|
+
width={32}
|
|
39
|
+
height={32}
|
|
40
|
+
imgScale={2}
|
|
41
|
+
centered
|
|
42
|
+
/>
|
|
43
|
+
</SpriteWrapper>
|
|
44
|
+
<ColName>
|
|
45
|
+
<BlueprintName>{blueprint.name}</BlueprintName>
|
|
46
|
+
{(blueprint.type || blueprint.subType) && (
|
|
47
|
+
<BlueprintMeta>
|
|
48
|
+
{[blueprint.type, blueprint.subType]
|
|
49
|
+
.filter(Boolean)
|
|
50
|
+
.filter((v, i, arr) => arr.indexOf(v) === i)
|
|
51
|
+
.join(' · ')}
|
|
52
|
+
</BlueprintMeta>
|
|
53
|
+
)}
|
|
54
|
+
</ColName>
|
|
55
|
+
<ColType>
|
|
56
|
+
<TypeText>{blueprint.type}</TypeText>
|
|
57
|
+
{blueprint.subType && blueprint.subType !== blueprint.type && (
|
|
58
|
+
<SubTypeText>{blueprint.subType}</SubTypeText>
|
|
59
|
+
)}
|
|
60
|
+
</ColType>
|
|
61
|
+
<ColTier>T{blueprint.tier}</ColTier>
|
|
62
|
+
</ResultRow>
|
|
63
|
+
))}
|
|
64
|
+
</>
|
|
65
|
+
);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const tableRowBase = `
|
|
69
|
+
display: grid;
|
|
70
|
+
grid-template-columns: 40px 1fr 120px 50px;
|
|
71
|
+
align-items: center;
|
|
72
|
+
gap: 8px;
|
|
73
|
+
padding: 6px 12px;
|
|
74
|
+
`;
|
|
75
|
+
|
|
76
|
+
const ResultsHeader = styled.div`
|
|
77
|
+
${tableRowBase}
|
|
78
|
+
background: rgba(0, 0, 0, 0.4);
|
|
79
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
|
80
|
+
position: sticky;
|
|
81
|
+
top: 0;
|
|
82
|
+
z-index: 1;
|
|
83
|
+
|
|
84
|
+
> * {
|
|
85
|
+
font-size: 0.45rem;
|
|
86
|
+
color: #888;
|
|
87
|
+
text-transform: uppercase;
|
|
88
|
+
letter-spacing: 1px;
|
|
89
|
+
}
|
|
90
|
+
`;
|
|
91
|
+
|
|
92
|
+
const ResultRow = styled.div<{ $selectable: boolean }>`
|
|
93
|
+
${tableRowBase}
|
|
94
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.04);
|
|
95
|
+
cursor: ${p => p.$selectable ? 'pointer' : 'default'};
|
|
96
|
+
transition: background 0.1s;
|
|
97
|
+
|
|
98
|
+
&:hover {
|
|
99
|
+
background: ${p => p.$selectable ? 'rgba(245, 158, 11, 0.08)' : 'none'};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
&:last-child {
|
|
103
|
+
border-bottom: none;
|
|
104
|
+
}
|
|
105
|
+
`;
|
|
106
|
+
|
|
107
|
+
const SpriteWrapper = styled.div`
|
|
108
|
+
display: flex;
|
|
109
|
+
align-items: center;
|
|
110
|
+
justify-content: center;
|
|
111
|
+
width: 40px;
|
|
112
|
+
height: 32px;
|
|
113
|
+
`;
|
|
114
|
+
|
|
115
|
+
const ColName = styled.div`
|
|
116
|
+
display: flex;
|
|
117
|
+
flex-direction: column;
|
|
118
|
+
gap: 2px;
|
|
119
|
+
overflow: hidden;
|
|
120
|
+
`;
|
|
121
|
+
|
|
122
|
+
const BlueprintName = styled.span`
|
|
123
|
+
font-size: 0.5rem;
|
|
124
|
+
color: #ddd;
|
|
125
|
+
overflow: hidden;
|
|
126
|
+
text-overflow: ellipsis;
|
|
127
|
+
white-space: nowrap;
|
|
128
|
+
`;
|
|
129
|
+
|
|
130
|
+
const BlueprintMeta = styled.span`
|
|
131
|
+
font-size: 0.4rem;
|
|
132
|
+
color: #666;
|
|
133
|
+
overflow: hidden;
|
|
134
|
+
text-overflow: ellipsis;
|
|
135
|
+
white-space: nowrap;
|
|
136
|
+
`;
|
|
137
|
+
|
|
138
|
+
const ColType = styled.div`
|
|
139
|
+
display: flex;
|
|
140
|
+
flex-direction: column;
|
|
141
|
+
gap: 2px;
|
|
142
|
+
`;
|
|
143
|
+
|
|
144
|
+
const TypeText = styled.span`
|
|
145
|
+
font-size: 0.45rem;
|
|
146
|
+
color: #aaa;
|
|
147
|
+
`;
|
|
148
|
+
|
|
149
|
+
const SubTypeText = styled.span`
|
|
150
|
+
font-size: 0.4rem;
|
|
151
|
+
color: #666;
|
|
152
|
+
`;
|
|
153
|
+
|
|
154
|
+
const ColTier = styled.div`
|
|
155
|
+
font-size: 0.5rem;
|
|
156
|
+
color: #f59e0b;
|
|
157
|
+
text-align: center;
|
|
158
|
+
`;
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
import { ShoppingCart } from 'pixelarticons/react/ShoppingCart';
|
|
5
5
|
import React from 'react';
|
|
6
6
|
import { FaTimes } from 'react-icons/fa';
|
|
7
|
-
import styled from 'styled-components';
|
|
7
|
+
import styled, { keyframes } from 'styled-components';
|
|
8
8
|
import { Dropdown } from '../Dropdown';
|
|
9
9
|
import { IOptionsProps } from '../Dropdown';
|
|
10
10
|
import { Input } from '../Input';
|
|
@@ -25,8 +25,15 @@ export interface IBuyOrderDetailsModalProps {
|
|
|
25
25
|
onConfirm: () => void;
|
|
26
26
|
atlasJSON: any;
|
|
27
27
|
atlasIMG: any;
|
|
28
|
+
enableHotkeys?: () => void;
|
|
29
|
+
disableHotkeys?: () => void;
|
|
28
30
|
}
|
|
29
31
|
|
|
32
|
+
const scaleIn = keyframes`
|
|
33
|
+
from { transform: scale(0.85); opacity: 0; }
|
|
34
|
+
to { transform: scale(1); opacity: 1; }
|
|
35
|
+
`;
|
|
36
|
+
|
|
30
37
|
const rarityOptions: IOptionsProps[] = [
|
|
31
38
|
{ id: 1, value: 'Common', option: 'Common' },
|
|
32
39
|
{ id: 2, value: 'Uncommon', option: 'Uncommon' },
|
|
@@ -48,6 +55,8 @@ export const BuyOrderDetailsModal: React.FC<IBuyOrderDetailsModalProps> = ({
|
|
|
48
55
|
onConfirm,
|
|
49
56
|
atlasJSON,
|
|
50
57
|
atlasIMG,
|
|
58
|
+
enableHotkeys,
|
|
59
|
+
disableHotkeys,
|
|
51
60
|
}) => {
|
|
52
61
|
if (!isOpen || !blueprint) return null;
|
|
53
62
|
|
|
@@ -89,7 +98,7 @@ export const BuyOrderDetailsModal: React.FC<IBuyOrderDetailsModalProps> = ({
|
|
|
89
98
|
</SpriteWrapper>
|
|
90
99
|
<ItemInfo>
|
|
91
100
|
<ItemName>{blueprint.name}</ItemName>
|
|
92
|
-
<
|
|
101
|
+
<ItemMeta>{[blueprint.type, blueprint.subType].filter(Boolean).filter((v, i, arr) => arr.indexOf(v) === i).join(' · ')} · T{blueprint.tier}</ItemMeta>
|
|
93
102
|
</ItemInfo>
|
|
94
103
|
</ItemDisplay>
|
|
95
104
|
|
|
@@ -102,6 +111,8 @@ export const BuyOrderDetailsModal: React.FC<IBuyOrderDetailsModalProps> = ({
|
|
|
102
111
|
placeholder="Qty"
|
|
103
112
|
type="number"
|
|
104
113
|
min={1}
|
|
114
|
+
onFocus={disableHotkeys}
|
|
115
|
+
onBlur={enableHotkeys}
|
|
105
116
|
/>
|
|
106
117
|
</FieldRow>
|
|
107
118
|
|
|
@@ -113,6 +124,8 @@ export const BuyOrderDetailsModal: React.FC<IBuyOrderDetailsModalProps> = ({
|
|
|
113
124
|
placeholder="Max gold"
|
|
114
125
|
type="number"
|
|
115
126
|
min={1}
|
|
127
|
+
onFocus={disableHotkeys}
|
|
128
|
+
onBlur={enableHotkeys}
|
|
116
129
|
/>
|
|
117
130
|
</FieldRow>
|
|
118
131
|
|
|
@@ -170,12 +183,7 @@ const ModalContent = styled.div`
|
|
|
170
183
|
flex-direction: column;
|
|
171
184
|
gap: 16px;
|
|
172
185
|
pointer-events: auto;
|
|
173
|
-
animation: scaleIn 0.15s ease-out;
|
|
174
|
-
|
|
175
|
-
@keyframes scaleIn {
|
|
176
|
-
from { transform: scale(0.85); opacity: 0; }
|
|
177
|
-
to { transform: scale(1); opacity: 1; }
|
|
178
|
-
}
|
|
186
|
+
animation: ${scaleIn} 0.15s ease-out;
|
|
179
187
|
`;
|
|
180
188
|
|
|
181
189
|
const Header = styled.div`
|
|
@@ -238,7 +246,7 @@ const ItemName = styled.span`
|
|
|
238
246
|
white-space: nowrap;
|
|
239
247
|
`;
|
|
240
248
|
|
|
241
|
-
const
|
|
249
|
+
const ItemMeta = styled.span`
|
|
242
250
|
font-size: 0.4rem;
|
|
243
251
|
color: #666;
|
|
244
252
|
overflow: hidden;
|
|
@@ -270,7 +278,6 @@ const Label = styled.label`
|
|
|
270
278
|
`;
|
|
271
279
|
|
|
272
280
|
const StyledInput = styled(Input)`
|
|
273
|
-
height: 10px;
|
|
274
281
|
width: 100%;
|
|
275
282
|
`;
|
|
276
283
|
|