astrogators-shared-ui 0.5.0 → 0.7.0-rc.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 +132 -196
- package/dist/index.css +2 -0
- package/dist/index.js +732 -805
- package/dist/{components → src/components}/display/Badge.d.ts +0 -1
- package/dist/{components → src/components}/display/Card.d.ts +0 -1
- package/dist/{components → src/components}/display/Modal.d.ts +0 -1
- package/dist/{components → src/components}/feedback/Loader.d.ts +0 -1
- package/dist/{components → src/components}/forms/AllyCodeDropdown.d.ts +0 -1
- package/dist/{components → src/components}/forms/Button.d.ts +0 -1
- package/dist/{components → src/components}/forms/Input.d.ts +0 -1
- package/dist/{components → src/components}/forms/Select.d.ts +0 -1
- package/dist/{components → src/components}/layout/Container.d.ts +0 -1
- package/dist/{components → src/components}/layout/Footer.d.ts +0 -1
- package/dist/{components → src/components}/layout/TopBar.d.ts +0 -1
- package/dist/{contexts → src/contexts}/AuthContext.d.ts +0 -1
- package/dist/{index.d.ts → src/index.d.ts} +0 -1
- package/package.json +22 -14
- package/dist/style.css +0 -1
- /package/dist/{components → src/components}/display/index.d.ts +0 -0
- /package/dist/{components → src/components}/feedback/index.d.ts +0 -0
- /package/dist/{components → src/components}/forms/index.d.ts +0 -0
- /package/dist/{components → src/components}/layout/index.d.ts +0 -0
- /package/dist/{services → src/services}/allyCodeStorage.d.ts +0 -0
- /package/dist/{services → src/services}/api.d.ts +0 -0
- /package/dist/{services → src/services}/auth.d.ts +0 -0
- /package/dist/{types → src/types}/api.d.ts +0 -0
- /package/dist/{types → src/types}/index.d.ts +0 -0
- /package/dist/{types → src/types}/mod.d.ts +0 -0
- /package/dist/{types → src/types}/user.d.ts +0 -0
- /package/dist/{utils → src/utils}/formatAllyCode.d.ts +0 -0
package/README.md
CHANGED
|
@@ -1,169 +1,116 @@
|
|
|
1
1
|
# @psytor/astrogators-shared-ui
|
|
2
2
|
|
|
3
|
-
Shared
|
|
3
|
+
Shared React components, auth, and API client for the Astrogator's Table
|
|
4
|
+
frontends (`astrogators-hub`, `mod-ledger-ui`). Published to GitHub Packages.
|
|
5
|
+
|
|
6
|
+
This is a library — there is no app shell here. See `PUBLISHING.md` for the
|
|
7
|
+
release flow and `CLAUDE.md` for architecture notes.
|
|
4
8
|
|
|
5
9
|
## Installation
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
|
|
11
|
+
The package is hosted on GitHub Packages, so consumers need an `.npmrc`
|
|
12
|
+
pointing the `@psytor` scope at the right registry:
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
@psytor:registry=https://npm.pkg.github.com
|
|
16
|
+
//npm.pkg.github.com/:_authToken=${GITHUB_PAT}
|
|
9
17
|
```
|
|
10
18
|
|
|
11
|
-
|
|
19
|
+
The PAT needs `read:packages` scope. Then:
|
|
12
20
|
|
|
13
|
-
|
|
21
|
+
```bash
|
|
22
|
+
npm install @psytor/astrogators-shared-ui
|
|
23
|
+
```
|
|
14
24
|
|
|
15
|
-
|
|
25
|
+
Peer dependencies: `react` and `react-dom` (18 or 19).
|
|
16
26
|
|
|
17
|
-
|
|
18
|
-
import { initializeApiClient } from '@psytor/astrogators-shared-ui';
|
|
27
|
+
## Setup
|
|
19
28
|
|
|
20
|
-
|
|
21
|
-
baseURL: 'http://localhost:8000', // Your backend API URL
|
|
22
|
-
onUnauthorized: () => {
|
|
23
|
-
// Handle unauthorized (e.g., redirect to login)
|
|
24
|
-
window.location.href = '/login';
|
|
25
|
-
},
|
|
26
|
-
});
|
|
27
|
-
```
|
|
29
|
+
### 1. Wrap the app in `AuthProvider`
|
|
28
30
|
|
|
29
|
-
|
|
31
|
+
`AuthProvider` initializes the API client with the given `apiBaseUrl` and
|
|
32
|
+
manages auth, feature flags, and ally codes for the whole app. Pass the
|
|
33
|
+
**prefixed** backend URL — workspace backends mount their routes under
|
|
34
|
+
`/<service-name>` (see the workspace `CLAUDE.md`).
|
|
30
35
|
|
|
31
36
|
```tsx
|
|
32
37
|
import { AuthProvider } from '@psytor/astrogators-shared-ui';
|
|
38
|
+
import '@psytor/astrogators-shared-ui/styles';
|
|
33
39
|
|
|
34
40
|
function App() {
|
|
35
41
|
return (
|
|
36
|
-
<AuthProvider>
|
|
37
|
-
{/*
|
|
42
|
+
<AuthProvider apiBaseUrl={import.meta.env.VITE_API_BASE_URL}>
|
|
43
|
+
{/* your app */}
|
|
38
44
|
</AuthProvider>
|
|
39
45
|
);
|
|
40
46
|
}
|
|
41
47
|
```
|
|
42
48
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
```tsx
|
|
46
|
-
import '@psytor/astrogators-shared-ui/styles';
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
## Components
|
|
49
|
+
`VITE_API_BASE_URL` looks like `http://localhost:8000/astrogators-table` in
|
|
50
|
+
dev.
|
|
50
51
|
|
|
51
|
-
###
|
|
52
|
+
### 2. (Optional) Reconfigure the API client
|
|
52
53
|
|
|
53
|
-
|
|
54
|
+
`AuthProvider` already calls `initializeApiClient`. Call it yourself only if
|
|
55
|
+
you need a custom `onUnauthorized` handler (e.g. router-driven redirects):
|
|
54
56
|
|
|
55
57
|
```tsx
|
|
56
|
-
import {
|
|
58
|
+
import { initializeApiClient } from '@psytor/astrogators-shared-ui';
|
|
57
59
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
initializeApiClient({
|
|
61
|
+
baseURL: import.meta.env.VITE_API_BASE_URL,
|
|
62
|
+
onUnauthorized: () => navigate('/login'),
|
|
63
|
+
});
|
|
62
64
|
```
|
|
63
65
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
```tsx
|
|
67
|
-
import { Container } from '@psytor/astrogators-shared-ui';
|
|
66
|
+
## Components
|
|
68
67
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
```
|
|
68
|
+
All components are styled via CSS Modules and the global design tokens in
|
|
69
|
+
`./styles`. Override the design system by redefining CSS variables on `:root`
|
|
70
|
+
(see "Theming").
|
|
73
71
|
|
|
74
|
-
|
|
72
|
+
### Layout
|
|
75
73
|
|
|
76
74
|
```tsx
|
|
77
|
-
import { Footer } from '@psytor/astrogators-shared-ui';
|
|
75
|
+
import { TopBar, Container, Footer } from '@psytor/astrogators-shared-ui';
|
|
78
76
|
|
|
77
|
+
<TopBar logo={<Logo />} rightContent={<UserMenu />} />
|
|
78
|
+
<Container maxWidth="lg" padding>{children}</Container>
|
|
79
79
|
<Footer />
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
-
###
|
|
83
|
-
|
|
84
|
-
#### Button
|
|
82
|
+
### Forms
|
|
85
83
|
|
|
86
84
|
```tsx
|
|
87
|
-
import { Button } from '@psytor/astrogators-shared-ui';
|
|
85
|
+
import { Button, Input, Select, AllyCodeDropdown } from '@psytor/astrogators-shared-ui';
|
|
88
86
|
|
|
89
|
-
<Button variant="primary" size="md"
|
|
90
|
-
|
|
91
|
-
|
|
87
|
+
<Button variant="primary" size="md" loading={submitting}>Save</Button>
|
|
88
|
+
<Input label="Email" type="email" required error={errors.email} />
|
|
89
|
+
<Select label="Profile" options={profiles} placeholder="Choose…" />
|
|
92
90
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
91
|
+
// Wired into useAuth — manages the user's ally codes (DB-backed when
|
|
92
|
+
// authenticated, localStorage when anonymous):
|
|
93
|
+
<AllyCodeDropdown />
|
|
96
94
|
```
|
|
97
95
|
|
|
98
|
-
|
|
96
|
+
`Button` variants: `primary | secondary | outline | ghost | danger`.
|
|
99
97
|
|
|
100
|
-
|
|
101
|
-
import { Input } from '@psytor/astrogators-shared-ui';
|
|
102
|
-
|
|
103
|
-
<Input
|
|
104
|
-
label="Email"
|
|
105
|
-
type="email"
|
|
106
|
-
placeholder="Enter your email"
|
|
107
|
-
required
|
|
108
|
-
error={errors.email}
|
|
109
|
-
/>
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
#### Select
|
|
98
|
+
### Display
|
|
113
99
|
|
|
114
100
|
```tsx
|
|
115
|
-
import {
|
|
116
|
-
|
|
117
|
-
<Select
|
|
118
|
-
label="Choose Profile"
|
|
119
|
-
options={[
|
|
120
|
-
{ value: 'standard', label: 'Standard' },
|
|
121
|
-
{ value: 'speed', label: 'Speed Focus' },
|
|
122
|
-
]}
|
|
123
|
-
placeholder="Select a profile"
|
|
124
|
-
/>
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
### Display Components
|
|
128
|
-
|
|
129
|
-
#### Card
|
|
130
|
-
|
|
131
|
-
```tsx
|
|
132
|
-
import { Card } from '@psytor/astrogators-shared-ui';
|
|
101
|
+
import { Card, Badge, Modal } from '@psytor/astrogators-shared-ui';
|
|
133
102
|
|
|
134
103
|
<Card variant="elevated" chamfered chamferSize="md" padding="lg" hoverable>
|
|
135
|
-
|
|
136
|
-
<p>Analyze your mods</p>
|
|
104
|
+
…
|
|
137
105
|
</Card>
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
#### Badge
|
|
141
|
-
|
|
142
|
-
```tsx
|
|
143
|
-
import { Badge } from '@psytor/astrogators-shared-ui';
|
|
144
106
|
|
|
145
107
|
<Badge variant="success">Active</Badge>
|
|
146
108
|
<Badge variant="warning" size="sm">Beta</Badge>
|
|
147
|
-
```
|
|
148
109
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
```tsx
|
|
152
|
-
import { Modal } from '@psytor/astrogators-shared-ui';
|
|
153
|
-
|
|
154
|
-
<Modal
|
|
155
|
-
isOpen={isOpen}
|
|
156
|
-
onClose={() => setIsOpen(false)}
|
|
157
|
-
title="Login"
|
|
158
|
-
size="md"
|
|
159
|
-
>
|
|
160
|
-
{/* Modal content */}
|
|
161
|
-
</Modal>
|
|
110
|
+
<Modal isOpen={open} onClose={close} title="Login" size="md">…</Modal>
|
|
162
111
|
```
|
|
163
112
|
|
|
164
|
-
### Feedback
|
|
165
|
-
|
|
166
|
-
#### Loader
|
|
113
|
+
### Feedback
|
|
167
114
|
|
|
168
115
|
```tsx
|
|
169
116
|
import { Loader } from '@psytor/astrogators-shared-ui';
|
|
@@ -174,82 +121,96 @@ import { Loader } from '@psytor/astrogators-shared-ui';
|
|
|
174
121
|
|
|
175
122
|
## Authentication
|
|
176
123
|
|
|
177
|
-
|
|
124
|
+
`useAuth` returns the full auth + ally-code surface. The hook must be called
|
|
125
|
+
inside `AuthProvider`.
|
|
178
126
|
|
|
179
127
|
```tsx
|
|
180
128
|
import { useAuth } from '@psytor/astrogators-shared-ui';
|
|
181
129
|
|
|
182
|
-
|
|
183
|
-
|
|
130
|
+
const {
|
|
131
|
+
// session
|
|
132
|
+
user, isAuthenticated, isLoading,
|
|
133
|
+
login, register, logout, refreshUser,
|
|
134
|
+
forgotPassword, resetPassword, resendVerification,
|
|
184
135
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
await login({
|
|
188
|
-
email: 'user@example.com',
|
|
189
|
-
password: 'password',
|
|
190
|
-
});
|
|
191
|
-
} catch (error) {
|
|
192
|
-
console.error('Login failed:', error);
|
|
193
|
-
}
|
|
194
|
-
};
|
|
136
|
+
// backend feature flags (e.g. auth_enabled)
|
|
137
|
+
authEnabled, isLoadingFeatures,
|
|
195
138
|
|
|
196
|
-
|
|
139
|
+
// ally codes — DB-backed when logged in, localStorage when anonymous
|
|
140
|
+
allyCodes, selectedAllyCode, isLoadingAllyCodes,
|
|
141
|
+
fetchAllyCodes, addAllyCode, removeAllyCode,
|
|
142
|
+
selectAllyCode, updateAllyCodeLastUsed,
|
|
197
143
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
<p>Welcome, {user?.username}!</p>
|
|
203
|
-
<button onClick={logout}>Logout</button>
|
|
204
|
-
</div>
|
|
205
|
-
) : (
|
|
206
|
-
<button onClick={handleLogin}>Login</button>
|
|
207
|
-
)}
|
|
208
|
-
</div>
|
|
209
|
-
);
|
|
210
|
-
}
|
|
144
|
+
// localStorage → DB migration prompt for users who sign up after
|
|
145
|
+
// adding ally codes anonymously
|
|
146
|
+
migrationPrompt, dismissMigrationPrompt, migrateLocalStorageCodes,
|
|
147
|
+
} = useAuth();
|
|
211
148
|
```
|
|
212
149
|
|
|
213
|
-
|
|
150
|
+
Tokens are stored in `localStorage`. Registration does **not** auto-login —
|
|
151
|
+
it requires email verification.
|
|
214
152
|
|
|
215
|
-
|
|
153
|
+
## API client
|
|
216
154
|
|
|
217
155
|
```tsx
|
|
218
156
|
import { apiClient } from '@psytor/astrogators-shared-ui';
|
|
219
157
|
|
|
220
|
-
|
|
221
|
-
const data = await apiClient.get('/api/v1/game-data/characters');
|
|
222
|
-
|
|
223
|
-
// POST request
|
|
158
|
+
const characters = await apiClient.get('/api/v1/game-data/characters');
|
|
224
159
|
const result = await apiClient.post('/api/v1/mod-ledger/evaluate/123456789', {
|
|
225
160
|
profile_name: 'standard',
|
|
226
161
|
});
|
|
227
162
|
```
|
|
228
163
|
|
|
229
|
-
The
|
|
230
|
-
-
|
|
231
|
-
-
|
|
232
|
-
|
|
233
|
-
-
|
|
164
|
+
The client:
|
|
165
|
+
- injects the access token into `Authorization`
|
|
166
|
+
- on `401`, transparently refreshes via `/api/v1/auth/refresh-token` and
|
|
167
|
+
retries the original request once
|
|
168
|
+
- calls `onUnauthorized` if refresh fails
|
|
234
169
|
|
|
235
|
-
|
|
170
|
+
Endpoints are written **without** the service prefix — the prefix lives in
|
|
171
|
+
the configured `baseURL`.
|
|
236
172
|
|
|
237
|
-
|
|
173
|
+
## Ally code utilities
|
|
174
|
+
|
|
175
|
+
For UI that needs to format/validate the 9-digit SWGOH player IDs outside the
|
|
176
|
+
context of `useAuth`:
|
|
177
|
+
|
|
178
|
+
```tsx
|
|
179
|
+
import {
|
|
180
|
+
formatAllyCode, // "123456789" → "123-456-789"
|
|
181
|
+
unformatAllyCode, // "123-456-789" → "123456789"
|
|
182
|
+
getAllyCodesFromStorage,
|
|
183
|
+
saveAllyCodeToStorage,
|
|
184
|
+
removeAllyCodeFromStorage,
|
|
185
|
+
getSelectedAllyCode,
|
|
186
|
+
setSelectedAllyCode,
|
|
187
|
+
clearAllyCodes,
|
|
188
|
+
} from '@psytor/astrogators-shared-ui';
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Prefer `useAuth` when you can — it keeps DB and localStorage in sync.
|
|
192
|
+
|
|
193
|
+
## TypeScript
|
|
194
|
+
|
|
195
|
+
All public types are re-exported from the package root, including:
|
|
238
196
|
|
|
239
197
|
```tsx
|
|
240
198
|
import type {
|
|
241
|
-
User,
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
ModEvaluation,
|
|
246
|
-
ApiError,
|
|
199
|
+
User, LoginRequest, LoginResponse,
|
|
200
|
+
RegisterRequest, ForgotPasswordRequest, ResetPasswordRequest,
|
|
201
|
+
AllyCode, AllyCodeCreate, AllyCodeListResponse, StoredAllyCode,
|
|
202
|
+
ApiResponse, ApiError, PaginatedResponse,
|
|
203
|
+
ParsedMod, ModStat, ModEvaluation, EvaluationRequest, EvaluationResponse,
|
|
247
204
|
} from '@psytor/astrogators-shared-ui';
|
|
248
205
|
```
|
|
249
206
|
|
|
250
|
-
|
|
207
|
+
Consumers should set `"moduleResolution": "bundler"` (or `"node16"`) in
|
|
208
|
+
`tsconfig.json` so the bundled `.d.ts` files resolve.
|
|
209
|
+
|
|
210
|
+
## Theming
|
|
251
211
|
|
|
252
|
-
|
|
212
|
+
Design tokens are CSS variables on `:root`. Override anything you need in
|
|
213
|
+
your own stylesheet, loaded after the library styles:
|
|
253
214
|
|
|
254
215
|
```css
|
|
255
216
|
:root {
|
|
@@ -261,57 +222,32 @@ Customize the design system by overriding CSS variables:
|
|
|
261
222
|
}
|
|
262
223
|
```
|
|
263
224
|
|
|
264
|
-
|
|
225
|
+
### Chamfered boxes
|
|
265
226
|
|
|
266
|
-
|
|
227
|
+
Sci-fi cut-corner effect, available as utility classes or via `Card`:
|
|
267
228
|
|
|
268
229
|
```tsx
|
|
269
|
-
<div className="chamfered-box">
|
|
270
|
-
|
|
271
|
-
|
|
230
|
+
<div className="chamfered-box">…</div>
|
|
231
|
+
<div className="chamfered-box-sm">…</div>
|
|
232
|
+
<div className="chamfered-box-lg">…</div>
|
|
272
233
|
|
|
273
|
-
<
|
|
274
|
-
{/* Large chamfered corners */}
|
|
275
|
-
</div>
|
|
276
|
-
|
|
277
|
-
<div className="chamfered-box-sm">
|
|
278
|
-
{/* Small chamfered corners */}
|
|
279
|
-
</div>
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
Or use the Card component:
|
|
283
|
-
|
|
284
|
-
```tsx
|
|
285
|
-
<Card chamfered chamferSize="lg">
|
|
286
|
-
{/* Content */}
|
|
287
|
-
</Card>
|
|
234
|
+
<Card chamfered chamferSize="lg">…</Card>
|
|
288
235
|
```
|
|
289
236
|
|
|
290
237
|
## Development
|
|
291
238
|
|
|
292
239
|
```bash
|
|
293
|
-
# Install dependencies
|
|
294
240
|
npm install
|
|
295
|
-
|
|
296
|
-
#
|
|
297
|
-
npm run build
|
|
298
|
-
|
|
299
|
-
# Type check
|
|
300
|
-
npm run type-check
|
|
241
|
+
npm run build # tsc && vite build → dist/
|
|
242
|
+
npm run type-check # tsc --noEmit
|
|
301
243
|
```
|
|
302
244
|
|
|
303
|
-
|
|
245
|
+
There is no `dev` server worth running (this is a library, not an app).
|
|
246
|
+
Iterate by rebuilding and reinstalling in a consumer, or `npm link`.
|
|
304
247
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
# Build
|
|
310
|
-
npm run build
|
|
311
|
-
|
|
312
|
-
# Publish to GitHub Packages
|
|
313
|
-
npm publish
|
|
314
|
-
```
|
|
248
|
+
See `PUBLISHING.md` for the release procedure. The non-negotiable rule:
|
|
249
|
+
**always `npm run build` before `npm publish`** — `dist/` is gitignored but
|
|
250
|
+
is the only thing shipped, so skipping the build re-publishes stale code.
|
|
315
251
|
|
|
316
252
|
## License
|
|
317
253
|
|