@pitvox/partner-react 0.3.0 → 0.4.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 +76 -166
- package/dist/index.cjs +1 -1
- package/dist/index.js +922 -997
- package/dist/styles.css +379 -0
- package/package.json +3 -4
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# @pitvox/partner-react
|
|
2
2
|
|
|
3
|
-
React SDK for PitVox partner websites. Provides hooks, components, and
|
|
3
|
+
React SDK for PitVox partner websites. Provides hooks, styled components, and a driver dashboard for sim racing communities affiliated with [PitVox](https://pitvox.com).
|
|
4
|
+
|
|
5
|
+
**Hooks-first**: Use the data hooks with any UI framework (Tailwind, DaisyUI, Shadcn, Preline, etc.). The styled `pvx-*` components are optional building blocks for quick starts.
|
|
4
6
|
|
|
5
7
|
## Installation
|
|
6
8
|
|
|
@@ -10,10 +12,8 @@ npm install @pitvox/partner-react
|
|
|
10
12
|
|
|
11
13
|
### Peer dependencies
|
|
12
14
|
|
|
13
|
-
The SDK requires these in your project:
|
|
14
|
-
|
|
15
15
|
```bash
|
|
16
|
-
npm install react react-dom @tanstack/react-query
|
|
16
|
+
npm install react react-dom @tanstack/react-query
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
## Quick start
|
|
@@ -25,14 +25,12 @@ import { PitVoxPartnerProvider } from '@pitvox/partner-react'
|
|
|
25
25
|
|
|
26
26
|
function App() {
|
|
27
27
|
return (
|
|
28
|
-
<
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
</PitVoxPartnerProvider>
|
|
35
|
-
</BrowserRouter>
|
|
28
|
+
<PitVoxPartnerProvider
|
|
29
|
+
partnerSlug="your-slug"
|
|
30
|
+
getSteamId={() => currentUser?.steamId ?? null}
|
|
31
|
+
>
|
|
32
|
+
{/* your app */}
|
|
33
|
+
</PitVoxPartnerProvider>
|
|
36
34
|
)
|
|
37
35
|
}
|
|
38
36
|
```
|
|
@@ -41,48 +39,7 @@ function App() {
|
|
|
41
39
|
|
|
42
40
|
## Leaderboards
|
|
43
41
|
|
|
44
|
-
###
|
|
45
|
-
|
|
46
|
-
One component gives you a complete 4-layer leaderboard with game tabs, version selector, tag filtering, sortable columns, sector highlighting, and drill-down navigation:
|
|
47
|
-
|
|
48
|
-
```jsx
|
|
49
|
-
import { LeaderboardExplorer } from '@pitvox/partner-react'
|
|
50
|
-
import '@pitvox/partner-react/styles.css'
|
|
51
|
-
|
|
52
|
-
function LeaderboardsPage() {
|
|
53
|
-
return <LeaderboardExplorer />
|
|
54
|
-
}
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
The `LeaderboardExplorer` manages all state via URL search parameters (`?game=evo&track=...&car=...&driver=...`), so deep-linking and browser back/forward work out of the box.
|
|
58
|
-
|
|
59
|
-
**Props:**
|
|
60
|
-
|
|
61
|
-
| Prop | Type | Default | Description |
|
|
62
|
-
|------|------|---------|-------------|
|
|
63
|
-
| `className` | `string` | — | Additional class on root container |
|
|
64
|
-
| `defaultGame` | `'evo' \| 'acc'` | `'evo'` | Default game tab |
|
|
65
|
-
| `title` | `string` | `'Leaderboards'` | Page heading |
|
|
66
|
-
|
|
67
|
-
### Layer components
|
|
68
|
-
|
|
69
|
-
For more control, use the individual layer components directly. Each handles its own sorting, filtering, and highlighting logic:
|
|
70
|
-
|
|
71
|
-
```jsx
|
|
72
|
-
import { TracksTable, CarsTable, DriversTable, LapHistoryTable } from '@pitvox/partner-react'
|
|
73
|
-
import '@pitvox/partner-react/styles.css'
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
- **`<TracksTable>`** — Layer 1: all tracks with record holders, tag filtering
|
|
77
|
-
- **`<CarsTable>`** — Layer 2: cars for a selected track, tag filtering
|
|
78
|
-
- **`<DriversTable>`** — Layer 3: drivers for a car with sectors (S1/S2/S3), tyre, fuel
|
|
79
|
-
- **`<LapHistoryTable>`** — Layer 4: driver's lap history with validity and personal best highlighting
|
|
80
|
-
|
|
81
|
-
You're responsible for wiring up the navigation between layers and managing URL state.
|
|
82
|
-
|
|
83
|
-
### Hooks only
|
|
84
|
-
|
|
85
|
-
For fully custom UIs, use the data hooks directly:
|
|
42
|
+
### Hooks
|
|
86
43
|
|
|
87
44
|
```jsx
|
|
88
45
|
import {
|
|
@@ -96,12 +53,11 @@ import {
|
|
|
96
53
|
|
|
97
54
|
**`useLeaderboardIndex(options?)`** — Fetch all tracks with record holders.
|
|
98
55
|
- `options.game` — Filter by game (`'evo'` | `'acc'`)
|
|
99
|
-
- `
|
|
100
|
-
- Returns `{ data: Track[], isLoading, partner, generatedAt, totalLaps, totalUsers, versions }`
|
|
56
|
+
- Returns `{ data: Track[], isLoading, generatedAt, totalLaps, totalUsers, versions }`
|
|
101
57
|
|
|
102
58
|
**`useTrackLeaderboard(trackId, layout?, options?)`** — Fetch track entries.
|
|
103
|
-
- Without `options.carId`: returns best lap per car (
|
|
104
|
-
- With `options.carId`: returns all drivers for that car (
|
|
59
|
+
- Without `options.carId`: returns best lap per car (car-level)
|
|
60
|
+
- With `options.carId`: returns all drivers for that car (driver-level)
|
|
105
61
|
- Returns `{ data: Entry[], isLoading, error }`
|
|
106
62
|
|
|
107
63
|
**`useDriverLaps(userId, trackId, layout, carId, options?)`** — Fetch a driver's lap history.
|
|
@@ -112,58 +68,25 @@ import {
|
|
|
112
68
|
|
|
113
69
|
**`useCarMetadata()`** — Returns `{ tags: string[], cars: Record<string, { tags }> }` for tag filtering.
|
|
114
70
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
### Drop-in (recommended)
|
|
118
|
-
|
|
119
|
-
One component gives you a complete competition experience with card grid, championship standings, round-by-round results with session tabs, and entry lists:
|
|
120
|
-
|
|
121
|
-
```jsx
|
|
122
|
-
import { CompetitionExplorer } from '@pitvox/partner-react'
|
|
123
|
-
import '@pitvox/partner-react/styles.css'
|
|
124
|
-
|
|
125
|
-
function CompetitionsPage() {
|
|
126
|
-
return <CompetitionExplorer />
|
|
127
|
-
}
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
The `CompetitionExplorer` manages all state via URL search parameters (`?competition=abc123&tab=standings&round=2`), so deep-linking and browser back/forward work out of the box.
|
|
131
|
-
|
|
132
|
-
**Props:**
|
|
71
|
+
### Styled components
|
|
133
72
|
|
|
134
|
-
|
|
135
|
-
|------|------|---------|-------------|
|
|
136
|
-
| `className` | `string` | — | Additional class on root container |
|
|
137
|
-
| `title` | `string` | `'Competitions'` | Page heading |
|
|
138
|
-
|
|
139
|
-
**Features:**
|
|
140
|
-
- Competition card grid with poster images, type badges, format/car pills, schedule summary, registration status
|
|
141
|
-
- Championship standings with position rank badges, nation flags, wins/podiums columns, per-round cells with dropped round styling
|
|
142
|
-
- Round results with session tabs (Practice/Qualifying/Race), best lap with sector hover tooltip, podium highlighting
|
|
143
|
-
- Entry list with driver avatars
|
|
144
|
-
- Horizontal schedule strip with next-round highlighting
|
|
145
|
-
- Breadcrumb navigation between list and detail views
|
|
146
|
-
|
|
147
|
-
### Layer components
|
|
148
|
-
|
|
149
|
-
For more control, use the individual layer components directly:
|
|
73
|
+
For building leaderboard pages with the SDK's `pvx-*` styles:
|
|
150
74
|
|
|
151
75
|
```jsx
|
|
152
|
-
import {
|
|
76
|
+
import { TracksTable, CarsTable, DriversTable, LapHistoryTable } from '@pitvox/partner-react'
|
|
153
77
|
import '@pitvox/partner-react/styles.css'
|
|
154
78
|
```
|
|
155
79
|
|
|
156
|
-
- **`<
|
|
157
|
-
- **`<
|
|
158
|
-
- **`<
|
|
159
|
-
- **`<
|
|
160
|
-
- **`<RegisterButton>`** — Register/withdraw toggle (render prop or default button)
|
|
80
|
+
- **`<TracksTable>`** — All tracks with record holders, tag filtering, sorting
|
|
81
|
+
- **`<CarsTable>`** — Cars for a selected track with tag filtering
|
|
82
|
+
- **`<DriversTable>`** — Drivers for a car with sectors (S1/S2/S3), tyre, fuel
|
|
83
|
+
- **`<LapHistoryTable>`** — Driver's lap history with validity and personal best highlighting
|
|
161
84
|
|
|
162
|
-
You
|
|
85
|
+
You compose these into your own page layout and wire up navigation between layers. See the [partner templates](https://github.com/meekysoft/pitvox-partner-template) for a complete example using React Router.
|
|
163
86
|
|
|
164
|
-
|
|
87
|
+
## Competitions
|
|
165
88
|
|
|
166
|
-
|
|
89
|
+
### Hooks
|
|
167
90
|
|
|
168
91
|
```jsx
|
|
169
92
|
import {
|
|
@@ -187,13 +110,38 @@ import {
|
|
|
187
110
|
**`useCompetitionAllRounds(competitionId, roundNumbers)`** — Fetch multiple round results in parallel.
|
|
188
111
|
|
|
189
112
|
**`useCompetitionEntryList(competitionId)`** — Registered drivers.
|
|
113
|
+
|
|
114
|
+
### Styled components
|
|
115
|
+
|
|
116
|
+
```jsx
|
|
117
|
+
import {
|
|
118
|
+
CompetitionCards, StandingsTable, RoundResults, RoundSessionResults,
|
|
119
|
+
EntryList, RegisterButton, RegistrationPanel,
|
|
120
|
+
} from '@pitvox/partner-react'
|
|
121
|
+
import '@pitvox/partner-react/styles.css'
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
- **`<CompetitionCards>`** — Card grid with posters, type badges, schedule, registration status
|
|
125
|
+
- **`<StandingsTable>`** — Championship standings with per-round breakdowns, podium highlights
|
|
126
|
+
- **`<RoundResults>`** — Standalone round results (fetches data, renders header + sessions)
|
|
127
|
+
- **`<RoundSessionResults>`** — Session tabs + results table (data-prop driven, no fetch)
|
|
128
|
+
- **`<EntryList>`** — Registered drivers grid with avatars
|
|
129
|
+
- **`<RegisterButton>`** — Register/withdraw toggle (render prop or default button)
|
|
130
|
+
- **`<RegistrationPanel>`** — Registration form + entry list with unregister
|
|
131
|
+
|
|
132
|
+
### Shared utilities
|
|
133
|
+
|
|
134
|
+
Useful when composing competition pages:
|
|
135
|
+
|
|
136
|
+
```jsx
|
|
137
|
+
import { TypeBadge, InfoPill, PODIUM_MEDALS, CompLoadingState, CompEmptyState } from '@pitvox/partner-react'
|
|
190
138
|
```
|
|
191
139
|
|
|
192
140
|
## Driver Dashboard
|
|
193
141
|
|
|
194
|
-
### Drop-in
|
|
142
|
+
### Drop-in composite
|
|
195
143
|
|
|
196
|
-
|
|
144
|
+
The `DriverDashboard` is a self-contained component with no routing dependency:
|
|
197
145
|
|
|
198
146
|
```jsx
|
|
199
147
|
import { DriverDashboard } from '@pitvox/partner-react'
|
|
@@ -210,8 +158,6 @@ function DashboardPage() {
|
|
|
210
158
|
}
|
|
211
159
|
```
|
|
212
160
|
|
|
213
|
-
**Props:**
|
|
214
|
-
|
|
215
161
|
| Prop | Type | Default | Description |
|
|
216
162
|
|------|------|---------|-------------|
|
|
217
163
|
| `steamId` | `string` | — | Driver's Steam ID (required) |
|
|
@@ -219,50 +165,33 @@ function DashboardPage() {
|
|
|
219
165
|
| `memberSince` | `string` | — | ISO date for "Racing since" display |
|
|
220
166
|
| `className` | `string` | — | Additional class on root container |
|
|
221
167
|
|
|
222
|
-
**Displays:**
|
|
223
|
-
- Driver profile card (avatar, name, racing since)
|
|
224
|
-
- Stats cards: total laps (with track breakdown tooltip), cars used (with car breakdown tooltip), driver rating
|
|
225
|
-
- Current records list sorted by most recent, with track, car, lap time, and game badge
|
|
226
|
-
|
|
227
168
|
### Layer components
|
|
228
169
|
|
|
229
|
-
For more control, use the individual components directly:
|
|
230
|
-
|
|
231
170
|
```jsx
|
|
232
171
|
import { DriverProfile, StatsCards, RecordsTable } from '@pitvox/partner-react'
|
|
233
|
-
import '@pitvox/partner-react/styles.css'
|
|
234
172
|
```
|
|
235
173
|
|
|
236
|
-
|
|
237
|
-
- **`<StatsCards>`** — Stats cards with icons and hover breakdown tooltips (accepts `stats` from `useDriverStats` and `rating` from `useDriverRating`)
|
|
238
|
-
- **`<RecordsTable>`** — Compact records list sorted by most recent, with expand/collapse
|
|
239
|
-
|
|
240
|
-
### Hooks only
|
|
241
|
-
|
|
242
|
-
For fully custom UIs, use the data hooks directly:
|
|
174
|
+
### Hooks
|
|
243
175
|
|
|
244
176
|
```jsx
|
|
245
177
|
import { useDriverStats, useDriverRating } from '@pitvox/partner-react'
|
|
246
178
|
```
|
|
247
179
|
|
|
248
|
-
**`useDriverStats(steamId)`** —
|
|
249
|
-
- Shares the same query cache as `useDriverLaps` (same CDN file)
|
|
250
|
-
- Returns `{ data: { driverName, lapCount, trackBreakdown, carBreakdown, recordsHeld, currentRecords, bestRanking, bestRankingTrackId, bestRankingLayout, bestRankingCarId }, isLoading, error }`
|
|
180
|
+
**`useDriverStats(steamId)`** — Driver stats, records, and ranking from CDN.
|
|
251
181
|
|
|
252
|
-
**`useDriverRating(steamId)`** —
|
|
253
|
-
- Returns `{ data: { rating, rank, totalDrivers, comboCount, distinctCars, combos }, isLoading, error }`
|
|
182
|
+
**`useDriverRating(steamId)`** — Driver's rating from the partner ratings file.
|
|
254
183
|
|
|
255
184
|
## Registration
|
|
256
185
|
|
|
257
|
-
The SDK supports two registration modes, determined
|
|
186
|
+
The SDK supports two registration modes, determined by whether you provide callbacks to the provider.
|
|
258
187
|
|
|
259
188
|
### Basic mode (default)
|
|
260
189
|
|
|
261
|
-
No configuration needed.
|
|
190
|
+
No configuration needed. Registration components render links to pitvox.com where users register with Steam.
|
|
262
191
|
|
|
263
192
|
### Power mode
|
|
264
193
|
|
|
265
|
-
For partners with a backend (e.g.
|
|
194
|
+
For partners with a backend (e.g. Amplify Lambda proxying to pitvox-api), provide callbacks:
|
|
266
195
|
|
|
267
196
|
```jsx
|
|
268
197
|
<PitVoxPartnerProvider
|
|
@@ -277,29 +206,21 @@ For partners with a backend (e.g. an Amplify Lambda that proxies to pitvox-api),
|
|
|
277
206
|
>
|
|
278
207
|
```
|
|
279
208
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
### Hooks
|
|
209
|
+
### Registration hooks
|
|
283
210
|
|
|
284
211
|
```jsx
|
|
285
|
-
import {
|
|
286
|
-
useRegistrationStatus,
|
|
287
|
-
useRegister,
|
|
288
|
-
useWithdraw,
|
|
289
|
-
useRegistrationMode,
|
|
290
|
-
useRegistrationUrl,
|
|
291
|
-
} from '@pitvox/partner-react'
|
|
212
|
+
import { useRegistrationStatus, useRegister, useWithdraw, useRegistrationMode, useRegistrationUrl } from '@pitvox/partner-react'
|
|
292
213
|
```
|
|
293
214
|
|
|
294
|
-
**`useRegistrationStatus(competitionId)`** — Check if current user
|
|
215
|
+
**`useRegistrationStatus(competitionId)`** — Check if current user is registered.
|
|
295
216
|
|
|
296
|
-
**`useRegister(competitionId)`** —
|
|
217
|
+
**`useRegister(competitionId)`** — Mutation delegating to `onRegister` callback.
|
|
297
218
|
|
|
298
|
-
**`useWithdraw(competitionId)`** —
|
|
219
|
+
**`useWithdraw(competitionId)`** — Mutation delegating to `onWithdraw` callback.
|
|
299
220
|
|
|
300
|
-
**`useRegistrationMode()`** — Returns `{ isPowerMode, isBasicMode }
|
|
221
|
+
**`useRegistrationMode()`** — Returns `{ isPowerMode, isBasicMode }`.
|
|
301
222
|
|
|
302
|
-
**`useRegistrationUrl(competitionId)`** — Returns
|
|
223
|
+
**`useRegistrationUrl(competitionId)`** — Returns pitvox.com registration URL for basic mode.
|
|
303
224
|
|
|
304
225
|
## Formatting utilities
|
|
305
226
|
|
|
@@ -322,36 +243,25 @@ The default stylesheet uses CSS custom properties. Override them to match your b
|
|
|
322
243
|
|
|
323
244
|
```css
|
|
324
245
|
:root {
|
|
325
|
-
--pvx-accent: #e11d48;
|
|
326
|
-
--pvx-bg-card: #1a1a2e;
|
|
327
|
-
--pvx-sector-best: #22d3ee;
|
|
328
|
-
--pvx-rank-gold: #fbbf24;
|
|
246
|
+
--pvx-accent: #e11d48;
|
|
247
|
+
--pvx-bg-card: #1a1a2e;
|
|
248
|
+
--pvx-sector-best: #22d3ee;
|
|
249
|
+
--pvx-rank-gold: #fbbf24;
|
|
329
250
|
}
|
|
330
251
|
```
|
|
331
252
|
|
|
332
|
-
All classes are prefixed with `pvx-` to avoid collisions
|
|
253
|
+
All classes are prefixed with `pvx-` to avoid collisions. See `styles.css` for the full list of variables.
|
|
333
254
|
|
|
334
|
-
##
|
|
255
|
+
## Partner templates
|
|
335
256
|
|
|
336
|
-
|
|
257
|
+
For a complete working site using this SDK, see:
|
|
337
258
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
| Leaderboard index | `leaderboards/partners/{slug}/index.json` |
|
|
341
|
-
| Track entries | `leaderboards/partners/{slug}/tracks/{trackId}/{layout}.json` |
|
|
342
|
-
| Driver laps | `laps/partners/{slug}/{userId}.json` |
|
|
343
|
-
| User display names | `users/index.json` |
|
|
344
|
-
| Car metadata | `cars/index.json` |
|
|
345
|
-
| Competition index | `competitions/index.json` |
|
|
346
|
-
| Competition config | `competitions/{slug}/{id}/config.json` |
|
|
347
|
-
| Standings | `competitions/{slug}/{id}/standings.json` |
|
|
348
|
-
| Round results | `competitions/{slug}/{id}/rounds/{n}.json` |
|
|
349
|
-
| Entry list | `competitions/{slug}/{id}/entrylist.json` |
|
|
350
|
-
| Driver ratings | `leaderboards/partners/{slug}/ratings.json` |
|
|
259
|
+
- **[pitvox-partner-template](https://github.com/meekysoft/pitvox-partner-template)** — Basic template (no auth)
|
|
260
|
+
- **[pitvox-partner-template-amplify](https://github.com/meekysoft/pitvox-partner-template-amplify)** — AWS Amplify template with Steam auth and in-app registration
|
|
351
261
|
|
|
352
|
-
|
|
262
|
+
The templates demonstrate how to compose SDK hooks and components into full pages with routing.
|
|
353
263
|
|
|
354
|
-
|
|
264
|
+
## Local development
|
|
355
265
|
|
|
356
266
|
```bash
|
|
357
267
|
# In the SDK repo
|
|
@@ -367,7 +277,7 @@ Add `resolve.dedupe` to your Vite config to avoid duplicate React instances:
|
|
|
367
277
|
// vite.config.js
|
|
368
278
|
export default defineConfig({
|
|
369
279
|
resolve: {
|
|
370
|
-
dedupe: ['react', 'react-dom', '
|
|
280
|
+
dedupe: ['react', 'react-dom', '@tanstack/react-query'],
|
|
371
281
|
},
|
|
372
282
|
})
|
|
373
283
|
```
|