@rpg-engine/long-bow 0.8.160 → 0.8.161
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/Pager.d.ts +1 -0
- package/dist/long-bow.cjs.development.js +80 -38
- 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 +80 -38
- package/dist/long-bow.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Marketplace/BlueprintSearchModal.tsx +68 -29
- package/src/components/Marketplace/BlueprintTable.tsx +30 -21
- package/src/components/Pager.tsx +13 -5
package/package.json
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
import { debounce } from 'lodash';
|
|
7
7
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
8
8
|
import { FaTimes } from 'react-icons/fa';
|
|
9
|
+
import { SortVertical } from 'pixelarticons/react/SortVertical';
|
|
9
10
|
import styled, { keyframes } from 'styled-components';
|
|
10
11
|
import { Dropdown } from '../Dropdown';
|
|
11
12
|
import { IOptionsProps } from '../Dropdown';
|
|
@@ -67,6 +68,7 @@ export const BlueprintSearchModal: React.FC<IBlueprintSearchModalProps> = ({
|
|
|
67
68
|
const [searchName, setSearchName] = useState('');
|
|
68
69
|
const [selectedType, setSelectedType] = useState('');
|
|
69
70
|
const [selectedSubType, setSelectedSubType] = useState('');
|
|
71
|
+
const [showFilters, setShowFilters] = useState(false);
|
|
70
72
|
|
|
71
73
|
const searchNameRef = useRef(searchName);
|
|
72
74
|
const selectedTypeRef = useRef(selectedType);
|
|
@@ -154,22 +156,32 @@ export const BlueprintSearchModal: React.FC<IBlueprintSearchModalProps> = ({
|
|
|
154
156
|
onFocus={disableHotkeys}
|
|
155
157
|
onBlur={enableHotkeys}
|
|
156
158
|
/>
|
|
159
|
+
<FilterButton
|
|
160
|
+
type="button"
|
|
161
|
+
$active={showFilters}
|
|
162
|
+
onPointerDown={() => setShowFilters(v => !v)}
|
|
163
|
+
aria-label="Toggle filters"
|
|
164
|
+
>
|
|
165
|
+
<SortVertical width={16} height={16} />
|
|
166
|
+
</FilterButton>
|
|
157
167
|
</InputWrapper>
|
|
158
168
|
|
|
159
|
-
|
|
160
|
-
<
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
169
|
+
{showFilters && (
|
|
170
|
+
<FiltersRow>
|
|
171
|
+
<StyledDropdown
|
|
172
|
+
key={`type-${selectedType}`}
|
|
173
|
+
options={typeOptions}
|
|
174
|
+
onChange={handleTypeChange}
|
|
175
|
+
width="100%"
|
|
176
|
+
/>
|
|
177
|
+
<StyledDropdown
|
|
178
|
+
key={`subtype-${selectedSubType}`}
|
|
179
|
+
options={subTypeOptions}
|
|
180
|
+
onChange={handleSubTypeChange}
|
|
181
|
+
width="100%"
|
|
182
|
+
/>
|
|
183
|
+
</FiltersRow>
|
|
184
|
+
)}
|
|
173
185
|
|
|
174
186
|
<ResultsWrapper>
|
|
175
187
|
{blueprints.length === 0 && !isLoading ? (
|
|
@@ -191,14 +203,13 @@ export const BlueprintSearchModal: React.FC<IBlueprintSearchModalProps> = ({
|
|
|
191
203
|
)}
|
|
192
204
|
</ResultsWrapper>
|
|
193
205
|
|
|
194
|
-
<
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
</PagerContainer>
|
|
206
|
+
<Pager
|
|
207
|
+
compact
|
|
208
|
+
totalItems={totalCount}
|
|
209
|
+
currentPage={currentPage}
|
|
210
|
+
itemsPerPage={BLUEPRINTS_PER_PAGE}
|
|
211
|
+
onPageChange={handlePageChange}
|
|
212
|
+
/>
|
|
202
213
|
</ModalContent>
|
|
203
214
|
</ModalContainer>
|
|
204
215
|
</ModalPortal>
|
|
@@ -229,11 +240,21 @@ const ModalContent = styled.div`
|
|
|
229
240
|
padding: 20px 24px;
|
|
230
241
|
width: 600px;
|
|
231
242
|
max-width: 90%;
|
|
243
|
+
max-height: 90dvh;
|
|
232
244
|
display: flex;
|
|
233
245
|
flex-direction: column;
|
|
234
246
|
gap: 12px;
|
|
247
|
+
overflow: hidden;
|
|
235
248
|
pointer-events: auto;
|
|
236
249
|
animation: ${scaleIn} 0.15s ease-out;
|
|
250
|
+
|
|
251
|
+
@media (max-width: 950px) {
|
|
252
|
+
max-width: 96%;
|
|
253
|
+
max-height: 95dvh;
|
|
254
|
+
min-height: 75dvh;
|
|
255
|
+
padding: 14px 16px;
|
|
256
|
+
gap: 8px;
|
|
257
|
+
}
|
|
237
258
|
`;
|
|
238
259
|
|
|
239
260
|
const Header = styled.div`
|
|
@@ -288,6 +309,26 @@ const StyledInput = styled(Input)`
|
|
|
288
309
|
flex: 1;
|
|
289
310
|
`;
|
|
290
311
|
|
|
312
|
+
const FilterButton = styled.button<{ $active: boolean }>`
|
|
313
|
+
flex-shrink: 0;
|
|
314
|
+
width: 28px;
|
|
315
|
+
height: 28px;
|
|
316
|
+
border-radius: 6px;
|
|
317
|
+
border: 1px solid ${({ $active }) => ($active ? 'rgba(245, 158, 11, 0.55)' : 'rgba(255, 255, 255, 0.08)')};
|
|
318
|
+
background: ${({ $active }) => ($active ? 'rgba(245, 158, 11, 0.14)' : 'rgba(255, 255, 255, 0.03)')};
|
|
319
|
+
color: ${({ $active }) => ($active ? '#f59e0b' : '#ccc')};
|
|
320
|
+
cursor: pointer;
|
|
321
|
+
display: flex;
|
|
322
|
+
align-items: center;
|
|
323
|
+
justify-content: center;
|
|
324
|
+
transition: color 0.15s, border-color 0.15s, background 0.15s;
|
|
325
|
+
|
|
326
|
+
&:hover {
|
|
327
|
+
color: #f59e0b;
|
|
328
|
+
border-color: rgba(245, 158, 11, 0.45);
|
|
329
|
+
}
|
|
330
|
+
`;
|
|
331
|
+
|
|
291
332
|
const FiltersRow = styled.div`
|
|
292
333
|
display: grid;
|
|
293
334
|
grid-template-columns: 1fr 1fr;
|
|
@@ -302,7 +343,10 @@ const StyledDropdown = styled(Dropdown)`
|
|
|
302
343
|
const ResultsWrapper = styled.div`
|
|
303
344
|
position: relative;
|
|
304
345
|
overflow-y: auto;
|
|
305
|
-
|
|
346
|
+
flex: 1;
|
|
347
|
+
min-height: 80px;
|
|
348
|
+
display: flex;
|
|
349
|
+
flex-direction: column;
|
|
306
350
|
background: rgba(0, 0, 0, 0.2);
|
|
307
351
|
border: 1px solid rgba(255, 255, 255, 0.05);
|
|
308
352
|
border-radius: 4px;
|
|
@@ -333,17 +377,12 @@ const EmptyState = styled.div`
|
|
|
333
377
|
display: flex;
|
|
334
378
|
align-items: center;
|
|
335
379
|
justify-content: center;
|
|
336
|
-
|
|
380
|
+
flex: 1;
|
|
337
381
|
font-size: 0.55rem;
|
|
338
382
|
color: #666;
|
|
339
383
|
text-transform: uppercase;
|
|
340
384
|
letter-spacing: 1px;
|
|
341
385
|
`;
|
|
342
386
|
|
|
343
|
-
const PagerContainer = styled.div`
|
|
344
|
-
display: flex;
|
|
345
|
-
justify-content: center;
|
|
346
|
-
align-items: center;
|
|
347
|
-
`;
|
|
348
387
|
|
|
349
388
|
export { BLUEPRINTS_PER_PAGE };
|
|
@@ -42,9 +42,9 @@ export const BlueprintTable: React.FC<IBlueprintTableProps> = ({
|
|
|
42
42
|
atlasJSON={atlasJSON}
|
|
43
43
|
atlasIMG={atlasIMG}
|
|
44
44
|
spriteKey={blueprint.texturePath || blueprint.key}
|
|
45
|
-
width={
|
|
46
|
-
height={
|
|
47
|
-
imgScale={
|
|
45
|
+
width={24}
|
|
46
|
+
height={24}
|
|
47
|
+
imgScale={1.5}
|
|
48
48
|
centered
|
|
49
49
|
/>
|
|
50
50
|
</SpriteWrapper>
|
|
@@ -74,23 +74,31 @@ export const BlueprintTable: React.FC<IBlueprintTableProps> = ({
|
|
|
74
74
|
|
|
75
75
|
const tableRowBase = `
|
|
76
76
|
display: grid;
|
|
77
|
-
grid-template-columns:
|
|
77
|
+
grid-template-columns: 28px 1fr 100px 40px;
|
|
78
78
|
align-items: center;
|
|
79
|
-
gap:
|
|
80
|
-
padding:
|
|
79
|
+
gap: 6px;
|
|
80
|
+
padding: 3px 8px;
|
|
81
|
+
`;
|
|
82
|
+
|
|
83
|
+
const mobileRowOverride = `
|
|
84
|
+
@media (max-width: 600px) {
|
|
85
|
+
padding: 1px 6px;
|
|
86
|
+
gap: 4px;
|
|
87
|
+
}
|
|
81
88
|
`;
|
|
82
89
|
|
|
83
90
|
const ResultsHeader = styled.div`
|
|
84
91
|
${tableRowBase}
|
|
92
|
+
${mobileRowOverride}
|
|
85
93
|
background: rgba(0, 0, 0, 0.4);
|
|
86
94
|
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
|
87
95
|
position: sticky;
|
|
88
96
|
top: 0;
|
|
89
97
|
z-index: 1;
|
|
90
98
|
|
|
91
|
-
> * {
|
|
92
|
-
font-size: 0.
|
|
93
|
-
color: #
|
|
99
|
+
&& > * {
|
|
100
|
+
font-size: 0.48rem !important;
|
|
101
|
+
color: #555 !important;
|
|
94
102
|
text-transform: uppercase;
|
|
95
103
|
letter-spacing: 1px;
|
|
96
104
|
}
|
|
@@ -98,6 +106,7 @@ const ResultsHeader = styled.div`
|
|
|
98
106
|
|
|
99
107
|
const ResultRow = styled.div<{ $selectable: boolean }>`
|
|
100
108
|
${tableRowBase}
|
|
109
|
+
${mobileRowOverride}
|
|
101
110
|
border-bottom: 1px solid rgba(255, 255, 255, 0.04);
|
|
102
111
|
cursor: ${p => p.$selectable ? 'pointer' : 'default'};
|
|
103
112
|
transition: background 0.1s;
|
|
@@ -115,8 +124,8 @@ const SpriteWrapper = styled.div`
|
|
|
115
124
|
display: flex;
|
|
116
125
|
align-items: center;
|
|
117
126
|
justify-content: center;
|
|
118
|
-
width:
|
|
119
|
-
height:
|
|
127
|
+
width: 28px;
|
|
128
|
+
height: 24px;
|
|
120
129
|
`;
|
|
121
130
|
|
|
122
131
|
const ColName = styled.div`
|
|
@@ -127,16 +136,16 @@ const ColName = styled.div`
|
|
|
127
136
|
`;
|
|
128
137
|
|
|
129
138
|
const BlueprintName = styled.span`
|
|
130
|
-
font-size: 0.
|
|
131
|
-
color: #
|
|
139
|
+
font-size: 0.6rem !important;
|
|
140
|
+
color: #e5e7eb !important;
|
|
132
141
|
overflow: hidden;
|
|
133
142
|
text-overflow: ellipsis;
|
|
134
143
|
white-space: nowrap;
|
|
135
144
|
`;
|
|
136
145
|
|
|
137
146
|
const BlueprintMeta = styled.span`
|
|
138
|
-
font-size: 0.
|
|
139
|
-
color: #
|
|
147
|
+
font-size: 0.5rem !important;
|
|
148
|
+
color: #f59e0b !important;
|
|
140
149
|
overflow: hidden;
|
|
141
150
|
text-overflow: ellipsis;
|
|
142
151
|
white-space: nowrap;
|
|
@@ -149,17 +158,17 @@ const ColType = styled.div`
|
|
|
149
158
|
`;
|
|
150
159
|
|
|
151
160
|
const TypeText = styled.span`
|
|
152
|
-
font-size: 0.
|
|
153
|
-
color: #
|
|
161
|
+
font-size: 0.52rem !important;
|
|
162
|
+
color: #9ca3af !important;
|
|
154
163
|
`;
|
|
155
164
|
|
|
156
165
|
const SubTypeText = styled.span`
|
|
157
|
-
font-size: 0.
|
|
158
|
-
color: #
|
|
166
|
+
font-size: 0.46rem !important;
|
|
167
|
+
color: #f59e0b !important;
|
|
159
168
|
`;
|
|
160
169
|
|
|
161
170
|
const ColTier = styled.div`
|
|
162
|
-
font-size: 0.
|
|
163
|
-
color: #f59e0b;
|
|
171
|
+
font-size: 0.6rem !important;
|
|
172
|
+
color: #f59e0b !important;
|
|
164
173
|
text-align: center;
|
|
165
174
|
`;
|
package/src/components/Pager.tsx
CHANGED
|
@@ -8,6 +8,7 @@ interface PagerProps {
|
|
|
8
8
|
currentPage: number;
|
|
9
9
|
itemsPerPage: number;
|
|
10
10
|
onPageChange: (page: number) => void;
|
|
11
|
+
compact?: boolean;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
export const Pager: React.FC<PagerProps> = ({
|
|
@@ -15,13 +16,14 @@ export const Pager: React.FC<PagerProps> = ({
|
|
|
15
16
|
currentPage,
|
|
16
17
|
itemsPerPage,
|
|
17
18
|
onPageChange,
|
|
19
|
+
compact = false,
|
|
18
20
|
}) => {
|
|
19
21
|
const totalPages = Math.ceil(totalItems / itemsPerPage);
|
|
20
22
|
|
|
21
23
|
return (
|
|
22
24
|
<Container>
|
|
23
|
-
<p>Total items: {totalItems}</p>
|
|
24
|
-
<PagerContainer>
|
|
25
|
+
{!compact && <p>Total items: {totalItems}</p>}
|
|
26
|
+
<PagerContainer $compact={compact}>
|
|
25
27
|
<button
|
|
26
28
|
disabled={currentPage === 1}
|
|
27
29
|
onPointerDown={() => onPageChange(Math.max(currentPage - 1, 1))}
|
|
@@ -55,7 +57,7 @@ const Container = styled.div`
|
|
|
55
57
|
}
|
|
56
58
|
`;
|
|
57
59
|
|
|
58
|
-
const PagerContainer = styled.div
|
|
60
|
+
const PagerContainer = styled.div<{ $compact: boolean }>`
|
|
59
61
|
display: flex;
|
|
60
62
|
justify-content: center;
|
|
61
63
|
align-items: center;
|
|
@@ -67,11 +69,17 @@ const PagerContainer = styled.div`
|
|
|
67
69
|
|
|
68
70
|
div {
|
|
69
71
|
color: white;
|
|
72
|
+
${({ $compact }) => $compact && `
|
|
73
|
+
font-size: 0.55rem !important;
|
|
74
|
+
padding: 2px 6px !important;
|
|
75
|
+
min-width: unset !important;
|
|
76
|
+
`}
|
|
70
77
|
}
|
|
71
78
|
|
|
72
79
|
button {
|
|
73
|
-
width: 40px;
|
|
74
|
-
height: 40px;
|
|
80
|
+
width: ${({ $compact }) => ($compact ? '24px' : '40px')} !important;
|
|
81
|
+
height: ${({ $compact }) => ($compact ? '24px' : '40px')} !important;
|
|
82
|
+
font-size: ${({ $compact }) => ($compact ? '0.55rem' : 'inherit')} !important;
|
|
75
83
|
background-color: ${uiColors.darkGray};
|
|
76
84
|
border: none;
|
|
77
85
|
border-radius: 5px;
|