game-locker-ui 0.1.0
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/README.md +296 -0
- package/dist/game-locker-ui.js +15417 -0
- package/dist/game-locker-ui.js.map +1 -0
- package/dist/game-locker-ui.umd.cjs +15434 -0
- package/dist/game-locker-ui.umd.cjs.map +1 -0
- package/dist/index.d.ts +337 -0
- package/dist/style.css +10 -0
- package/package.json +106 -0
package/README.md
ADDED
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
# game-locker-ui
|
|
2
|
+
|
|
3
|
+
A React component kit for building game locker / loadout UIs. Fully themeable via CSS custom properties, written in TypeScript.
|
|
4
|
+
|
|
5
|
+
  
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install game-locker-ui
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
React 18 is a peer dependency — make sure it is already installed in your project.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
import { useState } from 'react';
|
|
23
|
+
import {
|
|
24
|
+
LockerThemeProvider,
|
|
25
|
+
LockerHeader,
|
|
26
|
+
LockerItemSlots,
|
|
27
|
+
CharacterDisplay,
|
|
28
|
+
LockerRightPanel,
|
|
29
|
+
} from 'game-locker-ui';
|
|
30
|
+
import 'game-locker-ui/styles';
|
|
31
|
+
|
|
32
|
+
export default function App() {
|
|
33
|
+
const [activeTab, setActiveTab] = useState('locker');
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<LockerThemeProvider>
|
|
37
|
+
<div style={{ display: 'flex', flexDirection: 'column', height: '100vh' }}>
|
|
38
|
+
<LockerHeader activeTab={activeTab} onTabChange={setActiveTab} />
|
|
39
|
+
<div style={{ display: 'flex', flex: 1, overflow: 'hidden' }}>
|
|
40
|
+
<LockerItemSlots />
|
|
41
|
+
<CharacterDisplay />
|
|
42
|
+
<LockerRightPanel />
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
</LockerThemeProvider>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
> **Important:** Import `'game-locker-ui/styles'` once at the top of your app. This injects the `--locker-*` CSS custom properties that all components depend on.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Components
|
|
55
|
+
|
|
56
|
+
### `LockerThemeProvider`
|
|
57
|
+
|
|
58
|
+
Wrap your app (or any subtree) with this provider to apply theme colors. All `--locker-*` CSS variables are scoped to the wrapper element — they don't pollute `:root` and are SSR-safe.
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
<LockerThemeProvider theme={{ bgDark: '#6c3483', selectionColor: '#00ffff' }}>
|
|
62
|
+
{/* components pick up the overrides automatically */}
|
|
63
|
+
</LockerThemeProvider>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
| Prop | Type | Default |
|
|
67
|
+
|------|------|---------|
|
|
68
|
+
| `theme` | `LockerTheme` | all defaults (see [Theming](#theming)) |
|
|
69
|
+
| `children` | `ReactNode` | — |
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
### `LockerHeader`
|
|
74
|
+
|
|
75
|
+
The top navigation bar with tab switching, a menu button with notification badge, and a currency counter.
|
|
76
|
+
|
|
77
|
+
```tsx
|
|
78
|
+
<LockerHeader
|
|
79
|
+
activeTab="locker"
|
|
80
|
+
onTabChange={(id) => console.log(id)}
|
|
81
|
+
vbucks={1200}
|
|
82
|
+
/>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
| Prop | Type | Default |
|
|
86
|
+
|------|------|---------|
|
|
87
|
+
| `activeTab` | `string` | — (required) |
|
|
88
|
+
| `onTabChange` | `(id: string) => void` | — (required) |
|
|
89
|
+
| `tabs` | `LockerTab[]` | 7 default tabs (see below) |
|
|
90
|
+
| `vbucks` | `number` | `800` |
|
|
91
|
+
| `notificationCount` | `number` | `1` |
|
|
92
|
+
|
|
93
|
+
**Default tabs:**
|
|
94
|
+
|
|
95
|
+
| id | label |
|
|
96
|
+
|----|-------|
|
|
97
|
+
| `play` | PLAY |
|
|
98
|
+
| `battlepass` | BATTLE PASS |
|
|
99
|
+
| `compete` | COMPETE |
|
|
100
|
+
| `locker` | LOCKER |
|
|
101
|
+
| `itemshop` | ITEM SHOP *(has notification badge)* |
|
|
102
|
+
| `career` | CAREER *(has notification badge)* |
|
|
103
|
+
| `vbucks` | V-BUCKS |
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
### `LockerItemSlots`
|
|
108
|
+
|
|
109
|
+
The left panel containing the main loadout row, emote wheel, miscellaneous slots, and a favorites button.
|
|
110
|
+
|
|
111
|
+
```tsx
|
|
112
|
+
<LockerItemSlots
|
|
113
|
+
topRowItems={myOutfits}
|
|
114
|
+
onItemSelect={(item) => console.log(item)}
|
|
115
|
+
favoriteActive
|
|
116
|
+
onFavoriteClick={() => {}}
|
|
117
|
+
/>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
| Prop | Type | Default |
|
|
121
|
+
|------|------|---------|
|
|
122
|
+
| `topRowItems` | `ItemSlot[]` | 5 placeholder slots (outfit, backbling, pickaxe, glider, contrail) |
|
|
123
|
+
| `emoteSlots` | `ItemSlot[]` | 6 placeholder slots (3 filled, 3 empty) |
|
|
124
|
+
| `miscSlots` | `ItemSlot[]` | 9 placeholder slots |
|
|
125
|
+
| `onItemSelect` | `(item: ItemSlot) => void` | — |
|
|
126
|
+
| `favoriteActive` | `boolean` | `false` |
|
|
127
|
+
| `onFavoriteClick` | `() => void` | — |
|
|
128
|
+
|
|
129
|
+
Supply an `image` URL on any `ItemSlot` to render it inside the slot:
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
const myItems: ItemSlot[] = [
|
|
133
|
+
{ id: '1', type: 'outfit', selected: true, image: 'https://example.com/skin.png', label: 'Dark Knight' },
|
|
134
|
+
{ id: '2', type: 'backbling' },
|
|
135
|
+
];
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
### `CharacterDisplay`
|
|
141
|
+
|
|
142
|
+
The center panel showing the character preview image, name, rarity, and category label.
|
|
143
|
+
|
|
144
|
+
```tsx
|
|
145
|
+
<CharacterDisplay
|
|
146
|
+
characterName="RAVEN"
|
|
147
|
+
rarityLabel="LEGENDARY"
|
|
148
|
+
categoryLabel="OUTFIT"
|
|
149
|
+
characterImage="https://example.com/raven.png"
|
|
150
|
+
/>
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
| Prop | Type | Default |
|
|
154
|
+
|------|------|---------|
|
|
155
|
+
| `characterImage` | `string` | Unsplash placeholder |
|
|
156
|
+
| `characterName` | `string` | `'SELENA'` |
|
|
157
|
+
| `rarityLabel` | `string` | `'EPIC'` |
|
|
158
|
+
| `categoryLabel` | `string` | `'OUTFIT'` |
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
### `LockerRightPanel`
|
|
163
|
+
|
|
164
|
+
The right panel with preset action buttons (Load, Save, Random).
|
|
165
|
+
|
|
166
|
+
```tsx
|
|
167
|
+
<LockerRightPanel
|
|
168
|
+
onLoad={() => loadPreset()}
|
|
169
|
+
onSave={() => savePreset()}
|
|
170
|
+
onRandom={() => randomize()}
|
|
171
|
+
/>
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
| Prop | Type | Default |
|
|
175
|
+
|------|------|---------|
|
|
176
|
+
| `title` | `string` | `'PRESETS'` |
|
|
177
|
+
| `loadLabel` | `string` | `'LOAD'` |
|
|
178
|
+
| `saveLabel` | `string` | `'SAVE'` |
|
|
179
|
+
| `randomLabel` | `string` | `'RANDOM'` |
|
|
180
|
+
| `onLoad` | `() => void` | — |
|
|
181
|
+
| `onSave` | `() => void` | — |
|
|
182
|
+
| `onRandom` | `() => void` | — |
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Theming
|
|
187
|
+
|
|
188
|
+
All colors are driven by CSS custom properties. Import the stylesheet and override any variable on a parent element — no CSS recompile needed.
|
|
189
|
+
|
|
190
|
+
### CSS variables
|
|
191
|
+
|
|
192
|
+
| Variable | Default | Used for |
|
|
193
|
+
|----------|---------|----------|
|
|
194
|
+
| `--locker-bg-light` | `#4a9fdb` | Background gradient top, slot borders |
|
|
195
|
+
| `--locker-bg-mid` | `#2b7fd4` | Background gradient middle, slot fill |
|
|
196
|
+
| `--locker-bg-dark` | `#1e5fb8` | Header, slot fill, button backgrounds |
|
|
197
|
+
| `--locker-bg-darker` | `#0d4494` | Currency counter background |
|
|
198
|
+
| `--locker-selection` | `#ff00ff` | Selected slot border and glow |
|
|
199
|
+
| `--locker-badge` | `#ffd700` | Notification badges |
|
|
200
|
+
| `--locker-glow` | `#5aaee8` | Character display radial glow |
|
|
201
|
+
| `--locker-font` | `'Luckiest Guy', ...` | Heading font stack |
|
|
202
|
+
|
|
203
|
+
### Via `LockerThemeProvider` (recommended)
|
|
204
|
+
|
|
205
|
+
```tsx
|
|
206
|
+
<LockerThemeProvider
|
|
207
|
+
theme={{
|
|
208
|
+
bgDark: '#6c3483',
|
|
209
|
+
bgMid: '#8e44ad',
|
|
210
|
+
bgLight: '#a569bd',
|
|
211
|
+
bgDarker: '#4a235a',
|
|
212
|
+
selectionColor: '#00ffff',
|
|
213
|
+
badgeColor: '#ff6b00',
|
|
214
|
+
}}
|
|
215
|
+
>
|
|
216
|
+
<YourApp />
|
|
217
|
+
</LockerThemeProvider>
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Via plain CSS (alternative)
|
|
221
|
+
|
|
222
|
+
```css
|
|
223
|
+
.my-custom-locker {
|
|
224
|
+
--locker-bg-dark: #1a3a2a;
|
|
225
|
+
--locker-selection: #00ff88;
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### `useLockerTheme()` hook
|
|
230
|
+
|
|
231
|
+
Read the current resolved theme values inside any child component:
|
|
232
|
+
|
|
233
|
+
```tsx
|
|
234
|
+
import { useLockerTheme } from 'game-locker-ui';
|
|
235
|
+
|
|
236
|
+
function MyComponent() {
|
|
237
|
+
const theme = useLockerTheme();
|
|
238
|
+
return <div style={{ color: theme.selectionColor }}>Selected</div>;
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## TypeScript Types
|
|
245
|
+
|
|
246
|
+
```ts
|
|
247
|
+
import type { ItemSlot, ItemSlotType, LockerTab, LockerTheme } from 'game-locker-ui';
|
|
248
|
+
|
|
249
|
+
type ItemSlotType =
|
|
250
|
+
| 'outfit' | 'backbling' | 'pickaxe' | 'glider' | 'contrail'
|
|
251
|
+
| 'emote' | 'spray' | 'emoticon' | 'banner' | 'music';
|
|
252
|
+
|
|
253
|
+
interface ItemSlot {
|
|
254
|
+
id: string;
|
|
255
|
+
type: ItemSlotType;
|
|
256
|
+
selected?: boolean;
|
|
257
|
+
image?: string;
|
|
258
|
+
isEmpty?: boolean;
|
|
259
|
+
label?: string;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
interface LockerTab {
|
|
263
|
+
id: string;
|
|
264
|
+
label: string;
|
|
265
|
+
hasNotification?: boolean;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
interface LockerTheme {
|
|
269
|
+
bgLight?: string;
|
|
270
|
+
bgMid?: string;
|
|
271
|
+
bgDark?: string;
|
|
272
|
+
bgDarker?: string;
|
|
273
|
+
selectionColor?: string;
|
|
274
|
+
badgeColor?: string;
|
|
275
|
+
fontFamily?: string;
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
## Development
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
npm install # install dependencies
|
|
285
|
+
npm run dev # start demo app at localhost:5173
|
|
286
|
+
npm run build # build demo app → dist-demo/
|
|
287
|
+
npm run build:lib # build npm package → dist/
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
The demo app (`src/app/App.tsx`) shows a working instance of the full locker layout and serves as a live development environment.
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
## License
|
|
295
|
+
|
|
296
|
+
MIT
|