@rpg-engine/long-bow 0.8.140 → 0.8.145

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 (68) hide show
  1. package/dist/components/Marketplace/BlueprintSearchModal.d.ts +17 -0
  2. package/dist/components/Marketplace/BuyOrderDetailsModal.d.ts +17 -0
  3. package/dist/components/Marketplace/BuyOrderPanel.d.ts +24 -0
  4. package/dist/components/Marketplace/BuyOrderRows.d.ts +13 -0
  5. package/dist/components/Marketplace/BuyPanel.d.ts +9 -1
  6. package/dist/components/Marketplace/HistoryPanel.d.ts +18 -0
  7. package/dist/components/Marketplace/ManagmentPanel.d.ts +4 -3
  8. package/dist/components/Marketplace/Marketplace.d.ts +38 -2
  9. package/dist/components/Marketplace/MarketplaceRows.d.ts +13 -1
  10. package/dist/components/Marketplace/MarketplaceSettingsPanel.d.ts +8 -0
  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/components/shared/Tabs/Tabs.d.ts +13 -0
  17. package/dist/components/shared/Tabs/index.d.ts +1 -0
  18. package/dist/index.d.ts +5 -0
  19. package/dist/long-bow.cjs.development.js +12074 -1449
  20. package/dist/long-bow.cjs.development.js.map +1 -1
  21. package/dist/long-bow.cjs.production.min.js +1 -1
  22. package/dist/long-bow.cjs.production.min.js.map +1 -1
  23. package/dist/long-bow.esm.js +12060 -1450
  24. package/dist/long-bow.esm.js.map +1 -1
  25. package/dist/stories/Features/marketplace/BlueprintSearchModal.stories.d.ts +1 -0
  26. package/dist/stories/Features/marketplace/BuyOrderPanel.stories.d.ts +1 -0
  27. package/dist/stories/Features/marketplace/BuyOrderRows.stories.d.ts +1 -0
  28. package/dist/stories/Features/marketplace/HistoryPanel.stories.d.ts +1 -0
  29. package/dist/stories/Features/trading/MarketplaceRows.stories.d.ts +2 -1
  30. package/dist/stories/UI/buttonsAndInputs/SegmentedToggle.stories.d.ts +6 -0
  31. package/dist/stories/UI/text/LabelPill.stories.d.ts +7 -0
  32. package/dist/utils/atlasUtils.d.ts +2 -0
  33. package/package.json +3 -2
  34. package/src/components/ConfirmModal.tsx +50 -27
  35. package/src/components/Marketplace/BlueprintSearchModal.tsx +418 -0
  36. package/src/components/Marketplace/BuyOrderDetailsModal.tsx +307 -0
  37. package/src/components/Marketplace/BuyOrderPanel.tsx +266 -0
  38. package/src/components/Marketplace/BuyOrderRows.tsx +287 -0
  39. package/src/components/Marketplace/BuyPanel.tsx +486 -170
  40. package/src/components/Marketplace/HistoryPanel.tsx +422 -0
  41. package/src/components/Marketplace/ManagmentPanel.tsx +176 -98
  42. package/src/components/Marketplace/Marketplace.tsx +227 -40
  43. package/src/components/Marketplace/MarketplaceBuyModal.tsx +1 -0
  44. package/src/components/Marketplace/MarketplaceRows.tsx +274 -80
  45. package/src/components/Marketplace/MarketplaceSettingsPanel.tsx +128 -0
  46. package/src/components/Store/CartView.tsx +11 -0
  47. package/src/components/Store/PaymentMethodModal.tsx +26 -9
  48. package/src/components/shared/LabelPill/LabelPill.tsx +45 -0
  49. package/src/components/shared/LabelPill/index.ts +1 -0
  50. package/src/components/shared/SegmentedToggle/SegmentedToggle.tsx +61 -0
  51. package/src/components/shared/SegmentedToggle/index.ts +1 -0
  52. package/src/components/shared/SpriteFromAtlas.tsx +7 -2
  53. package/src/components/shared/Tabs/Tabs.tsx +60 -0
  54. package/src/components/shared/Tabs/index.ts +1 -0
  55. package/src/index.tsx +5 -0
  56. package/src/mocks/atlas/items/items.json +33998 -25238
  57. package/src/mocks/atlas/items/items.png +0 -0
  58. package/src/mocks/itemContainer.mocks.ts +31 -0
  59. package/src/stories/Features/marketplace/BlueprintSearchModal.stories.tsx +145 -0
  60. package/src/stories/Features/marketplace/BuyOrderPanel.stories.tsx +207 -0
  61. package/src/stories/Features/marketplace/BuyOrderRows.stories.tsx +116 -0
  62. package/src/stories/Features/marketplace/HistoryPanel.stories.tsx +157 -0
  63. package/src/stories/Features/trading/Marketplace.stories.tsx +109 -0
  64. package/src/stories/Features/trading/MarketplaceRows.stories.tsx +11 -0
  65. package/src/stories/UI/buttonsAndInputs/SegmentedToggle.stories.tsx +54 -0
  66. package/src/stories/UI/text/LabelPill.stories.tsx +43 -0
  67. package/src/utils/__test__/atlasUtils.spec.ts +26 -0
  68. package/src/utils/atlasUtils.ts +80 -0
@@ -1,4 +1,5 @@
1
- import { Meta } from '@storybook/react';
1
+ import { Meta, Story } from '@storybook/react';
2
2
  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
+ export declare const HighStackQuantity: Story;
@@ -0,0 +1,6 @@
1
+ import { Meta } from '@storybook/react';
2
+ import { ISegmentedToggleProps } from '../../../components/shared/SegmentedToggle';
3
+ declare const meta: Meta;
4
+ export default meta;
5
+ export declare const MarketplaceModes: import("@storybook/csf").AnnotatedStoryFn<import("@storybook/react").ReactFramework, ISegmentedToggleProps>;
6
+ export declare const ShortOptions: import("@storybook/csf").AnnotatedStoryFn<import("@storybook/react").ReactFramework, ISegmentedToggleProps>;
@@ -0,0 +1,7 @@
1
+ import { Meta } from '@storybook/react';
2
+ import { ILabelPillProps } from '../../../components/shared/LabelPill';
3
+ declare const meta: Meta;
4
+ export default meta;
5
+ export declare const Default: import("@storybook/csf").AnnotatedStoryFn<import("@storybook/react").ReactFramework, ILabelPillProps>;
6
+ export declare const BuyRequest: import("@storybook/csf").AnnotatedStoryFn<import("@storybook/react").ReactFramework, ILabelPillProps>;
7
+ export declare const Status: import("@storybook/csf").AnnotatedStoryFn<import("@storybook/react").ReactFramework, ILabelPillProps>;
@@ -0,0 +1,2 @@
1
+ export declare const NO_IMAGE_SPRITE_KEY = "others/no-image.png";
2
+ export declare const resolveAtlasSpriteKey: (atlasJSON: any, spriteKey?: string | null | undefined) => string | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpg-engine/long-bow",
3
- "version": "0.8.140",
3
+ "version": "0.8.145",
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.83",
87
+ "@rpg-engine/shared": "file:../rpg-shared",
88
88
  "dayjs": "^1.11.2",
89
89
  "font-awesome": "^4.7.0",
90
90
  "fs-extra": "^10.1.0",
@@ -92,6 +92,7 @@
92
92
  "lodash-es": "^4.17.21",
93
93
  "mobx": "^6.6.0",
94
94
  "mobx-react": "^7.5.0",
95
+ "pixelarticons": "^2.0.2",
95
96
  "react-colorful": "^5.6.1",
96
97
  "react-draggable": "^4.4.5",
97
98
  "react-error-boundary": "^3.1.4",
@@ -1,4 +1,5 @@
1
1
  import React, { ReactNode, useCallback } from 'react';
2
+ import { FaTimes } from 'react-icons/fa';
2
3
  import styled, { createGlobalStyle } from 'styled-components';
3
4
  import ModalPortal from './Abstractions/ModalPortal';
4
5
  import { Button, ButtonTypes } from './Button';
@@ -66,6 +67,13 @@ export const ConfirmModal: React.FC<IConfirmModalProps> = ({
66
67
  onTouchMove={stopPropagationTouch}
67
68
  onPointerDown={stopPropagationPointer}
68
69
  >
70
+ <Header>
71
+ <Title>Confirm</Title>
72
+ <CloseButton onPointerDown={handleClose} aria-label="Close">
73
+ <FaTimes />
74
+ </CloseButton>
75
+ </Header>
76
+
69
77
  <MessageContainer>
70
78
  {typeof message === 'string' ? (
71
79
  <Message>{message}</Message>
@@ -134,61 +142,76 @@ const ModalContainer = styled.div`
134
142
  `;
135
143
 
136
144
  const ModalContent = styled.div`
137
- background-color: #2a2a2a;
138
- border: 2px solid #444;
145
+ background: #1a1a2e;
146
+ border: 2px solid #f59e0b;
139
147
  border-radius: 8px;
140
- padding: 20px;
148
+ padding: 20px 24px 24px;
141
149
  min-width: 300px;
142
150
  max-width: 90%;
143
- margin: 0 auto;
144
- animation: scaleIn 0.2s ease-out;
145
- transform-origin: center;
146
- box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5), 0 0 40px rgba(0, 0, 0, 0.3);
151
+ display: flex;
152
+ flex-direction: column;
153
+ gap: 16px;
147
154
  pointer-events: auto;
155
+ animation: scaleIn 0.15s ease-out;
148
156
 
149
157
  @keyframes scaleIn {
150
- from {
151
- transform: scale(0.8);
152
- opacity: 0;
153
- }
154
- to {
155
- transform: scale(1);
156
- opacity: 1;
157
- }
158
+ from { transform: scale(0.85); opacity: 0; }
159
+ to { transform: scale(1); opacity: 1; }
158
160
  }
159
161
 
160
162
  @media (max-width: 768px) {
161
- padding: 25px;
162
163
  width: 85%;
163
164
  }
164
165
  `;
165
166
 
167
+ const Header = styled.div`
168
+ display: flex;
169
+ align-items: center;
170
+ justify-content: space-between;
171
+ `;
172
+
173
+ const Title = styled.h3`
174
+ margin: 0;
175
+ font-family: 'Press Start 2P', cursive;
176
+ font-size: 0.7rem;
177
+ color: #fef08a;
178
+ `;
179
+
180
+ const CloseButton = styled.button`
181
+ background: none;
182
+ border: none;
183
+ color: rgba(255, 255, 255, 0.6);
184
+ cursor: pointer;
185
+ font-size: 1rem;
186
+ padding: 4px;
187
+ display: flex;
188
+ align-items: center;
189
+
190
+ &:hover {
191
+ color: #ffffff;
192
+ }
193
+ `;
194
+
166
195
  const MessageContainer = styled.div`
167
- margin-bottom: 20px;
168
196
  text-align: center;
169
197
  `;
170
198
 
171
199
  const Message = styled.p`
172
200
  margin: 0;
173
- font-size: 16px;
174
- color: #fff;
175
- text-shadow: 0 1px 0 rgba(0, 0, 0, 0.5);
176
-
177
- @media (max-width: 768px) {
178
- font-size: 18px;
179
- }
201
+ font-family: 'Press Start 2P', cursive;
202
+ font-size: 0.6rem;
203
+ color: rgba(255, 255, 255, 0.85);
204
+ line-height: 1.8;
180
205
  `;
181
206
 
182
207
  const ButtonsContainer = styled.div`
183
208
  display: flex;
184
209
  justify-content: center;
185
210
  gap: 20px;
211
+ margin-top: 4px;
186
212
 
187
213
  @media (max-width: 768px) {
188
214
  gap: 30px;
189
- /* Increase button size for better touch targets */
190
- transform: scale(1.1);
191
- margin-top: 5px;
192
215
  }
193
216
  `;
194
217
 
@@ -0,0 +1,418 @@
1
+ import {
2
+ IMarketplaceBlueprintSearchRequest,
3
+ IMarketplaceBlueprintSummary,
4
+ ItemSubType,
5
+ } from '@rpg-engine/shared';
6
+ import React, { useState } from 'react';
7
+ import { FaTimes } from 'react-icons/fa';
8
+ import styled from 'styled-components';
9
+ import { Dropdown } from '../Dropdown';
10
+ import { IOptionsProps } from '../Dropdown';
11
+ import { Input } from '../Input';
12
+ import { Pager } from '../Pager';
13
+ import ModalPortal from '../Abstractions/ModalPortal';
14
+ import { SpriteFromAtlas } from '../shared/SpriteFromAtlas';
15
+
16
+ export interface IBlueprintSearchModalProps {
17
+ isOpen: boolean;
18
+ onClose: () => void;
19
+ onSelect: (blueprint: IMarketplaceBlueprintSummary) => void;
20
+ onSearch: (request: IMarketplaceBlueprintSearchRequest) => void;
21
+ blueprints: IMarketplaceBlueprintSummary[];
22
+ totalCount: number;
23
+ currentPage: number;
24
+ isLoading: boolean;
25
+ atlasJSON: any;
26
+ atlasIMG: any;
27
+ }
28
+
29
+ const BLUEPRINTS_PER_PAGE = 10;
30
+
31
+ const typeOptions: IOptionsProps[] = [
32
+ { id: 1, value: '', option: 'All Types' },
33
+ ...Object.keys(ItemSubType)
34
+ .filter((t) => t !== 'DeadBody')
35
+ .map((t, index) => ({ id: index + 2, value: t, option: t })),
36
+ ];
37
+
38
+ const subTypeOptions: IOptionsProps[] = [
39
+ { id: 1, value: '', option: 'All Sub Types' },
40
+ ...Object.keys(ItemSubType)
41
+ .filter((t) => t !== 'DeadBody')
42
+ .map((t, index) => ({ id: index + 2, value: t, option: t })),
43
+ ];
44
+
45
+ export const BlueprintSearchModal: React.FC<IBlueprintSearchModalProps> = ({
46
+ isOpen,
47
+ onClose,
48
+ onSelect,
49
+ onSearch,
50
+ blueprints,
51
+ totalCount,
52
+ currentPage,
53
+ isLoading,
54
+ atlasJSON,
55
+ atlasIMG,
56
+ }) => {
57
+ const [searchName, setSearchName] = useState('');
58
+ const [selectedType, setSelectedType] = useState('');
59
+ const [selectedSubType, setSelectedSubType] = useState('');
60
+
61
+ if (!isOpen) return null;
62
+
63
+ const triggerSearch = (overrides?: Partial<{ name: string; itemType: string; itemSubType: string; page: number }>): void => {
64
+ onSearch({
65
+ npcId: '',
66
+ name: overrides?.name ?? searchName,
67
+ itemType: overrides?.itemType ?? selectedType,
68
+ itemSubType: overrides?.itemSubType ?? selectedSubType,
69
+ page: overrides?.page ?? 1,
70
+ limit: BLUEPRINTS_PER_PAGE,
71
+ });
72
+ };
73
+
74
+ const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
75
+ setSearchName(e.target.value);
76
+ triggerSearch({ name: e.target.value, page: 1 });
77
+ };
78
+
79
+ const handleTypeChange = (value: string): void => {
80
+ setSelectedType(value);
81
+ triggerSearch({ itemType: value, page: 1 });
82
+ };
83
+
84
+ const handleSubTypeChange = (value: string): void => {
85
+ setSelectedSubType(value);
86
+ triggerSearch({ itemSubType: value, page: 1 });
87
+ };
88
+
89
+ const handlePageChange = (page: number): void => {
90
+ triggerSearch({ page });
91
+ };
92
+
93
+ const stopPropagation = (e: React.MouseEvent | React.PointerEvent): void => {
94
+ e.stopPropagation();
95
+ };
96
+
97
+ const handleClose = (e: React.PointerEvent | React.MouseEvent): void => {
98
+ e.preventDefault();
99
+ e.stopPropagation();
100
+ onClose();
101
+ };
102
+
103
+ return (
104
+ <ModalPortal>
105
+ <Overlay onPointerDown={handleClose} />
106
+ <ModalContainer>
107
+ <ModalContent
108
+ onClick={stopPropagation as React.MouseEventHandler}
109
+ onPointerDown={stopPropagation as React.PointerEventHandler}
110
+ >
111
+ <Header>
112
+ <Title>Select Item</Title>
113
+ <CloseButton onPointerDown={handleClose} aria-label="Close">
114
+ <FaTimes />
115
+ </CloseButton>
116
+ </Header>
117
+
118
+ <InputWrapper>
119
+ <p>SEARCH</p>
120
+ <StyledInput
121
+ value={searchName}
122
+ onChange={handleNameChange}
123
+ placeholder="Search by name..."
124
+ />
125
+ </InputWrapper>
126
+
127
+ <FiltersRow>
128
+ <StyledDropdown
129
+ key={`type-${selectedType}`}
130
+ options={typeOptions}
131
+ onChange={handleTypeChange}
132
+ width="100%"
133
+ />
134
+ <StyledDropdown
135
+ key={`subtype-${selectedSubType}`}
136
+ options={subTypeOptions}
137
+ onChange={handleSubTypeChange}
138
+ width="100%"
139
+ />
140
+ </FiltersRow>
141
+
142
+ <ResultsWrapper>
143
+ {isLoading ? (
144
+ <EmptyState>Loading...</EmptyState>
145
+ ) : blueprints.length === 0 ? (
146
+ <EmptyState>No blueprints found</EmptyState>
147
+ ) : (
148
+ <>
149
+ <ResultsHeader>
150
+ <ColName>Name</ColName>
151
+ <ColType>Type</ColType>
152
+ <ColTier>Tier</ColTier>
153
+ </ResultsHeader>
154
+ {blueprints.map((blueprint) => (
155
+ <ResultRow
156
+ key={blueprint.key}
157
+ onPointerDown={() => onSelect(blueprint)}
158
+ >
159
+ <SpriteWrapper>
160
+ <SpriteFromAtlas
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
+ </>
184
+ )}
185
+ </ResultsWrapper>
186
+
187
+ <PagerContainer>
188
+ <Pager
189
+ totalItems={totalCount}
190
+ currentPage={currentPage}
191
+ itemsPerPage={BLUEPRINTS_PER_PAGE}
192
+ onPageChange={handlePageChange}
193
+ />
194
+ </PagerContainer>
195
+ </ModalContent>
196
+ </ModalContainer>
197
+ </ModalPortal>
198
+ );
199
+ };
200
+
201
+ const Overlay = styled.div`
202
+ position: fixed;
203
+ inset: 0;
204
+ background: rgba(0, 0, 0, 0.7);
205
+ z-index: 1000;
206
+ `;
207
+
208
+ const ModalContainer = styled.div`
209
+ position: fixed;
210
+ inset: 0;
211
+ display: flex;
212
+ align-items: center;
213
+ justify-content: center;
214
+ z-index: 1001;
215
+ pointer-events: none;
216
+ `;
217
+
218
+ const ModalContent = styled.div`
219
+ background: #1a1a2e;
220
+ border: 2px solid #f59e0b;
221
+ border-radius: 8px;
222
+ padding: 20px 24px;
223
+ width: 600px;
224
+ max-width: 90%;
225
+ display: flex;
226
+ flex-direction: column;
227
+ gap: 12px;
228
+ 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
+ }
235
+ `;
236
+
237
+ const Header = styled.div`
238
+ display: flex;
239
+ align-items: center;
240
+ justify-content: space-between;
241
+ `;
242
+
243
+ const Title = styled.h3`
244
+ margin: 0;
245
+ font-family: 'Press Start 2P', cursive;
246
+ font-size: 0.7rem;
247
+ color: #fef08a;
248
+ `;
249
+
250
+ const CloseButton = styled.button`
251
+ background: none;
252
+ border: none;
253
+ color: rgba(255, 255, 255, 0.6);
254
+ cursor: pointer;
255
+ font-size: 1rem;
256
+ padding: 4px;
257
+ display: flex;
258
+ align-items: center;
259
+ pointer-events: auto;
260
+
261
+ &:hover {
262
+ color: #ffffff;
263
+ }
264
+ `;
265
+
266
+ const InputWrapper = styled.div`
267
+ display: flex;
268
+ align-items: center;
269
+ gap: 12px;
270
+ padding: 8px 12px;
271
+ background: rgba(0, 0, 0, 0.2);
272
+ border-radius: 4px;
273
+ border: 1px solid rgba(255, 255, 255, 0.05);
274
+
275
+ p {
276
+ margin: 0;
277
+ font-size: 0.7rem;
278
+ color: #ccc;
279
+ text-transform: uppercase;
280
+ letter-spacing: 1px;
281
+ white-space: nowrap;
282
+ }
283
+ `;
284
+
285
+ const StyledInput = styled(Input)`
286
+ flex: 1;
287
+ height: 10px;
288
+ `;
289
+
290
+ const FiltersRow = styled.div`
291
+ display: grid;
292
+ grid-template-columns: 1fr 1fr;
293
+ gap: 8px;
294
+ `;
295
+
296
+ const StyledDropdown = styled(Dropdown)`
297
+ margin: 0px !important;
298
+ width: 100% !important;
299
+ `;
300
+
301
+ const ResultsWrapper = styled.div`
302
+ overflow-y: auto;
303
+ max-height: 320px;
304
+ background: rgba(0, 0, 0, 0.2);
305
+ border: 1px solid rgba(255, 255, 255, 0.05);
306
+ border-radius: 4px;
307
+ `;
308
+
309
+ const tableRowBase = `
310
+ display: grid;
311
+ grid-template-columns: 32px 1fr 120px 60px;
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
+ }
331
+ `;
332
+
333
+ const ResultRow = styled.div`
334
+ ${tableRowBase}
335
+ border-bottom: 1px solid rgba(255, 255, 255, 0.04);
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`
349
+ display: flex;
350
+ align-items: center;
351
+ justify-content: center;
352
+ width: 32px;
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;
393
+ `;
394
+
395
+ const ColTier = styled.div`
396
+ font-size: 0.5rem;
397
+ color: #f59e0b;
398
+ text-align: center;
399
+ `;
400
+
401
+ const EmptyState = styled.div`
402
+ display: flex;
403
+ align-items: center;
404
+ justify-content: center;
405
+ height: 100px;
406
+ font-size: 0.55rem;
407
+ color: #666;
408
+ text-transform: uppercase;
409
+ letter-spacing: 1px;
410
+ `;
411
+
412
+ const PagerContainer = styled.div`
413
+ display: flex;
414
+ justify-content: center;
415
+ align-items: center;
416
+ `;
417
+
418
+ export { BLUEPRINTS_PER_PAGE };