@welcome-back/brand 0.1.1 → 0.1.3
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 +437 -27
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,7 +1,29 @@
|
|
|
1
1
|
# @welcome-back/brand
|
|
2
2
|
|
|
3
|
-
WelcomeBack brand assets for React apps.
|
|
4
|
-
|
|
3
|
+
WelcomeBack brand assets for React apps.
|
|
4
|
+
|
|
5
|
+
Today the package has one component: **`RunnerLoader`**, the isotipo W running
|
|
6
|
+
left. Its legs swing on their hips and cross under the body while the body bobs.
|
|
7
|
+
Use it for loading moments that mean "on the way to the next step".
|
|
8
|
+
|
|
9
|
+
- React 18 or 19. Works in Next.js (App Router and Pages), Vite and plain React.
|
|
10
|
+
- No CSS import, no Tailwind, no bundler setup: the animation ships inside the SVG.
|
|
11
|
+
- Server-renderable: it shows before JavaScript loads. Works in React Server
|
|
12
|
+
Components (it uses only `useId`).
|
|
13
|
+
- ESM and CommonJS builds, so Jest suites load it with no transform setup.
|
|
14
|
+
|
|
15
|
+
## Contents
|
|
16
|
+
|
|
17
|
+
- [Install](#install)
|
|
18
|
+
- [Quick start](#quick-start)
|
|
19
|
+
- [API](#api)
|
|
20
|
+
- [Examples](#examples)
|
|
21
|
+
- [Accessibility](#accessibility)
|
|
22
|
+
- [Where to use it, and where not](#where-to-use-it-and-where-not)
|
|
23
|
+
- [Troubleshooting](#troubleshooting)
|
|
24
|
+
- [Develop](#develop)
|
|
25
|
+
- [Publish a change](#publish-a-change)
|
|
26
|
+
- [Source art](#source-art)
|
|
5
27
|
|
|
6
28
|
## Install
|
|
7
29
|
|
|
@@ -9,48 +31,436 @@ running left with its legs crossing under the body.
|
|
|
9
31
|
npm i @welcome-back/brand
|
|
10
32
|
```
|
|
11
33
|
|
|
12
|
-
|
|
13
|
-
the SVG. ESM and CommonJS builds, so Jest suites can load it too.
|
|
34
|
+
The package is public on npm. No token or `.npmrc` is needed.
|
|
14
35
|
|
|
15
|
-
##
|
|
36
|
+
## Quick start
|
|
16
37
|
|
|
17
38
|
```tsx
|
|
18
39
|
import { RunnerLoader } from "@welcome-back/brand";
|
|
19
40
|
|
|
20
|
-
|
|
21
|
-
<
|
|
22
|
-
|
|
41
|
+
export function Loading() {
|
|
42
|
+
return <RunnerLoader className="w-24" label="Loading" />;
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
That is all. Set a width, and the height follows the art.
|
|
47
|
+
|
|
48
|
+
## API
|
|
49
|
+
|
|
50
|
+
### Props
|
|
51
|
+
|
|
52
|
+
| Prop | Type | Default | What it does |
|
|
53
|
+
|---|---|---|---|
|
|
54
|
+
| `className` | `string` | — | Added after the built-in `wb-runner` class. Use it for size, color and the CSS variables below. |
|
|
55
|
+
| `label` | `string` | — | Accessible name. With a label the SVG is `role="img"` and screen readers announce it. Without a label it is `aria-hidden`: use that when a parent element already names the loading state. |
|
|
56
|
+
|
|
57
|
+
The component renders one `<svg>`. It takes no other props.
|
|
58
|
+
|
|
59
|
+
### CSS custom properties
|
|
60
|
+
|
|
61
|
+
You can set these in `className` (Tailwind arbitrary properties), in your own
|
|
62
|
+
CSS class, or on any ancestor element. Values inherit, so one setting on a
|
|
63
|
+
wrapper applies to all runners inside it.
|
|
64
|
+
|
|
65
|
+
| Property | Controls | Default | Notes |
|
|
66
|
+
|---|---|---|---|
|
|
67
|
+
| `color` | Ink of the W, legs and shoes | `currentColor` | Any Tailwind `text-*` class works. |
|
|
68
|
+
| `--wb-runner-pants` | Fill inside the pants | `Canvas` | Set it to the color **behind** the runner. The near leg covers the far leg when they cross, so the pants must be opaque. |
|
|
69
|
+
| `--wb-runner-step` | Duration of one step | `0.32s` | A full stride is two steps (0.64 s). Lower is faster. |
|
|
70
|
+
|
|
71
|
+
`Canvas` is the page background color that the browser uses for the current
|
|
72
|
+
`color-scheme`: white in light mode, near-black in dark mode. On any other
|
|
73
|
+
surface (a card, a tinted panel, a brand color) set `--wb-runner-pants`.
|
|
74
|
+
|
|
75
|
+
### Size guide
|
|
76
|
+
|
|
77
|
+
| Width | Use |
|
|
78
|
+
|---|---|
|
|
79
|
+
| 96–128 px | Full-screen or full-panel loading |
|
|
80
|
+
| 48–64 px | Loading inside a card or a list area |
|
|
81
|
+
| 32–40 px | Next to text ("Loading…") |
|
|
82
|
+
| under 32 px | Not recommended: the legs become unreadable. Use a plain spinner. |
|
|
83
|
+
|
|
84
|
+
## Examples
|
|
85
|
+
|
|
86
|
+
### Tailwind: size, color and speed in one `className`
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
<RunnerLoader className="w-16 text-foreground" />
|
|
90
|
+
|
|
91
|
+
// Faster (0.2 s per step) and in the muted text color:
|
|
92
|
+
<RunnerLoader className="w-16 text-muted-foreground [--wb-runner-step:0.2s]" />
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Plain CSS (no Tailwind)
|
|
96
|
+
|
|
97
|
+
```css
|
|
98
|
+
/* loading.css */
|
|
99
|
+
.page-loader {
|
|
100
|
+
width: 112px;
|
|
101
|
+
color: #171717;
|
|
102
|
+
--wb-runner-pants: #ffffff;
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
import "./loading.css";
|
|
108
|
+
|
|
109
|
+
<RunnerLoader className="page-loader" label="Loading" />;
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Inline style on a wrapper
|
|
113
|
+
|
|
114
|
+
`RunnerLoader` has no `style` prop. The CSS variables inherit, so put inline
|
|
115
|
+
styles on a parent element. TypeScript does not know custom properties, so cast
|
|
116
|
+
the style object:
|
|
117
|
+
|
|
118
|
+
```tsx
|
|
119
|
+
import type { CSSProperties } from "react";
|
|
120
|
+
|
|
121
|
+
const runnerTheme = {
|
|
122
|
+
color: "#171717",
|
|
123
|
+
"--wb-runner-pants": "#F6F4E9",
|
|
124
|
+
"--wb-runner-step": "0.28s",
|
|
125
|
+
} as CSSProperties;
|
|
126
|
+
|
|
127
|
+
<div style={runnerTheme}>
|
|
128
|
+
<RunnerLoader className="w-24" label="Loading" />
|
|
129
|
+
</div>;
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Match a shadcn / Tailwind 3 theme token
|
|
133
|
+
|
|
134
|
+
shadcn stores colors as bare HSL values (`--background: 0 0% 100%`), so wrap
|
|
135
|
+
them in `hsl()`:
|
|
136
|
+
|
|
137
|
+
```tsx
|
|
138
|
+
<div className="bg-background text-foreground [--wb-runner-pants:hsl(var(--background))]">
|
|
139
|
+
<RunnerLoader className="w-24" />
|
|
140
|
+
</div>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
In Tailwind 4 the tokens are full colors, so drop the `hsl()`:
|
|
144
|
+
`[--wb-runner-pants:var(--background)]`.
|
|
145
|
+
|
|
146
|
+
### On a card or a colored surface
|
|
147
|
+
|
|
148
|
+
The pants must match the surface directly behind the runner, not the page:
|
|
149
|
+
|
|
150
|
+
```tsx
|
|
151
|
+
// On a card
|
|
152
|
+
<div className="rounded-xl bg-card p-8 [--wb-runner-pants:hsl(var(--card))]">
|
|
153
|
+
<RunnerLoader className="w-16" />
|
|
154
|
+
</div>
|
|
155
|
+
|
|
156
|
+
// On a brand-orange disc, with a cream runner
|
|
157
|
+
<div className="grid size-32 place-items-center rounded-full bg-[#FF6E26] text-[#FFFAF0] [--wb-runner-pants:#FF6E26]">
|
|
158
|
+
<RunnerLoader className="w-20" label="Loading" />
|
|
159
|
+
</div>
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Dark mode
|
|
163
|
+
|
|
164
|
+
With the defaults, no extra code is needed on the page background: `Canvas`
|
|
165
|
+
follows `color-scheme`, and the ink follows your text color.
|
|
166
|
+
|
|
167
|
+
```tsx
|
|
168
|
+
<main className="bg-background text-foreground">
|
|
169
|
+
<RunnerLoader className="w-24" />
|
|
170
|
+
</main>
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
If your dark mode is a `.dark` class and not `color-scheme`, set the pants from
|
|
174
|
+
the token, as in the shadcn example above.
|
|
175
|
+
|
|
176
|
+
### Next to text
|
|
177
|
+
|
|
178
|
+
The label is on the wrapper, so the runner stays decorative:
|
|
179
|
+
|
|
180
|
+
```tsx
|
|
181
|
+
<div role="status" className="flex items-center gap-3 text-sm text-muted-foreground">
|
|
182
|
+
<RunnerLoader className="w-9" />
|
|
183
|
+
<span>Loading your rewards…</span>
|
|
23
184
|
</div>
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Next.js route loading (`loading.tsx`)
|
|
188
|
+
|
|
189
|
+
```tsx
|
|
190
|
+
// app/dashboard/loading.tsx
|
|
191
|
+
import { RunnerLoader } from "@welcome-back/brand";
|
|
192
|
+
|
|
193
|
+
export default function Loading() {
|
|
194
|
+
return (
|
|
195
|
+
<div className="grid min-h-[60vh] place-items-center">
|
|
196
|
+
<RunnerLoader className="w-24" label="Loading" />
|
|
197
|
+
</div>
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
This is a Server Component. It needs no `"use client"`.
|
|
203
|
+
|
|
204
|
+
### React `Suspense` fallback
|
|
205
|
+
|
|
206
|
+
```tsx
|
|
207
|
+
<Suspense fallback={<RunnerLoader className="mx-auto w-20" label="Loading" />}>
|
|
208
|
+
<CustomerDetails id={id} />
|
|
209
|
+
</Suspense>
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Show only if the wait is long
|
|
213
|
+
|
|
214
|
+
On a fast request the runner can flash for a fraction of a stride. Wait before
|
|
215
|
+
you show it:
|
|
216
|
+
|
|
217
|
+
```tsx
|
|
218
|
+
"use client";
|
|
219
|
+
import { useEffect, useState } from "react";
|
|
220
|
+
import { RunnerLoader } from "@welcome-back/brand";
|
|
221
|
+
|
|
222
|
+
export function DelayedRunner({ delayMs = 200 }: { delayMs?: number }) {
|
|
223
|
+
const [visible, setVisible] = useState(false);
|
|
224
|
+
useEffect(() => {
|
|
225
|
+
const timer = setTimeout(() => setVisible(true), delayMs);
|
|
226
|
+
return () => clearTimeout(timer);
|
|
227
|
+
}, [delayMs]);
|
|
228
|
+
return visible ? <RunnerLoader className="w-16" label="Loading" /> : null;
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Full-screen splash
|
|
233
|
+
|
|
234
|
+
A server-rendered overlay covers the page before JavaScript runs. Hide it after
|
|
235
|
+
the app hydrates. This is a short version of staff-ui's `AppSplash`, which also
|
|
236
|
+
holds the splash for two strides on the first open of each session.
|
|
237
|
+
|
|
238
|
+
```tsx
|
|
239
|
+
"use client";
|
|
240
|
+
import { useEffect, useState } from "react";
|
|
241
|
+
import { RunnerLoader } from "@welcome-back/brand";
|
|
242
|
+
|
|
243
|
+
export function Splash() {
|
|
244
|
+
const [leaving, setLeaving] = useState(false);
|
|
245
|
+
const [gone, setGone] = useState(false);
|
|
246
|
+
|
|
247
|
+
useEffect(() => {
|
|
248
|
+
setLeaving(true);
|
|
249
|
+
const timer = setTimeout(() => setGone(true), 300); // fade duration
|
|
250
|
+
return () => clearTimeout(timer);
|
|
251
|
+
}, []);
|
|
252
|
+
|
|
253
|
+
if (gone) return null;
|
|
254
|
+
return (
|
|
255
|
+
<div
|
|
256
|
+
role="status"
|
|
257
|
+
aria-label="Loading"
|
|
258
|
+
className={`fixed inset-0 z-50 grid place-items-center bg-background text-foreground
|
|
259
|
+
[--wb-runner-pants:hsl(var(--background))] transition-opacity duration-300
|
|
260
|
+
${leaving ? "pointer-events-none opacity-0" : ""}`}
|
|
261
|
+
>
|
|
262
|
+
<RunnerLoader className="w-28" />
|
|
263
|
+
</div>
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Vite / plain React
|
|
269
|
+
|
|
270
|
+
Same import, no config:
|
|
271
|
+
|
|
272
|
+
```tsx
|
|
273
|
+
import { RunnerLoader } from "@welcome-back/brand";
|
|
274
|
+
|
|
275
|
+
function App() {
|
|
276
|
+
const { data, isLoading } = useQuery(/* … */);
|
|
277
|
+
if (isLoading) return <RunnerLoader className="loader" label="Loading" />;
|
|
278
|
+
return <Dashboard data={data} />;
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Jest and Testing Library
|
|
283
|
+
|
|
284
|
+
Jest loads the CommonJS build automatically. The SVG always has the class
|
|
285
|
+
`wb-runner`, so you can find it in tests:
|
|
286
|
+
|
|
287
|
+
```tsx
|
|
288
|
+
render(<Loading />);
|
|
289
|
+
expect(screen.getByRole("img", { name: "Loading" })).toHaveClass("wb-runner");
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
## Accessibility
|
|
293
|
+
|
|
294
|
+
- **Give exactly one accessible name per loading state.** Either put `label` on
|
|
295
|
+
the runner, or put `role="status"` and `aria-label` on its wrapper and leave
|
|
296
|
+
`label` out. Do not do both, or screen readers announce it twice.
|
|
297
|
+
- **Translate the label.** Pass it from your i18n layer, for example
|
|
298
|
+
`label={t("loading")}`.
|
|
299
|
+
- **Reduced motion is built in.** With `prefers-reduced-motion: reduce` the
|
|
300
|
+
runner holds one pose (legs apart, mid-stride), so the loading state is still
|
|
301
|
+
visible.
|
|
302
|
+
|
|
303
|
+
## Where to use it, and where not
|
|
304
|
+
|
|
305
|
+
| Use it | Do not use it |
|
|
306
|
+
|---|---|
|
|
307
|
+
| App open and splash screens | Inside buttons: at button size the legs cannot be read |
|
|
308
|
+
| Moves to the next step (after a scan, before a customer page) | Pages where the customer sees a business's own brand first (enrollment, card download): our W would lead over their brand |
|
|
309
|
+
| Route and Suspense fallbacks for a full page or panel | Every small wait: if it is everywhere, staff stop noticing it |
|
|
310
|
+
|
|
311
|
+
A skeleton is better when the layout that is coming is known: it shows where
|
|
312
|
+
the content will appear.
|
|
313
|
+
|
|
314
|
+
## Troubleshooting
|
|
315
|
+
|
|
316
|
+
| Symptom | Cause | Fix |
|
|
317
|
+
|---|---|---|
|
|
318
|
+
| The legs show a light or dark rectangle | `--wb-runner-pants` does not match the surface behind the runner | Set it to that surface color |
|
|
319
|
+
| The runner is invisible | Ink is the same color as the background | Set `color` / a `text-*` class |
|
|
320
|
+
| The runner does not move | The OS asks for reduced motion | Nothing to fix; this is intended |
|
|
321
|
+
| The runner fills the whole container | No width is set | Give it a width (`w-24`, or `width` in CSS) |
|
|
322
|
+
| A Tailwind arbitrary property has no effect | Tailwind does not scan the file | Check the `content` globs in the Tailwind config |
|
|
323
|
+
|
|
324
|
+
## Develop
|
|
325
|
+
|
|
326
|
+
### Repo layout
|
|
327
|
+
|
|
328
|
+
| Path | What it holds |
|
|
329
|
+
|---|---|
|
|
330
|
+
| `src/index.ts` | Public exports. Only what is exported here is part of the API. |
|
|
331
|
+
| `src/RunnerLoader.tsx` | The component: SVG structure, clip paths, props |
|
|
332
|
+
| `src/runnerCss.ts` | The animation: keyframes, timing, swing angles, reduced motion |
|
|
333
|
+
| `src/runnerArt.ts` | Vector data: paths, pants fills, clip polygons |
|
|
334
|
+
| `src/*.test.tsx` | Vitest tests (server render, no browser) |
|
|
335
|
+
| `scripts/mark-cjs.mjs` | Marks `dist/cjs` as CommonJS after the build |
|
|
336
|
+
| `.github/workflows/ci.yml` | Runs on every PR and on `main` |
|
|
337
|
+
| `.github/workflows/publish.yml` | Runs on a `v*` tag and publishes to npm |
|
|
338
|
+
|
|
339
|
+
### Commands
|
|
340
|
+
|
|
341
|
+
Node 22 or later.
|
|
24
342
|
|
|
25
|
-
|
|
26
|
-
|
|
343
|
+
```bash
|
|
344
|
+
npm ci # install
|
|
345
|
+
npm run typecheck # tsc, no output
|
|
346
|
+
npm test # vitest
|
|
347
|
+
npm run build # dist/esm (ESM + types) and dist/cjs (CommonJS)
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
CI runs all four, then loads both builds to prove that `import` and `require`
|
|
351
|
+
work.
|
|
352
|
+
|
|
353
|
+
### Try a change in an app before you publish
|
|
354
|
+
|
|
355
|
+
Pack the package and install the tarball in the app:
|
|
356
|
+
|
|
357
|
+
```bash
|
|
358
|
+
# in brand/
|
|
359
|
+
npm run build && npm pack # writes welcome-back-brand-<version>.tgz
|
|
360
|
+
|
|
361
|
+
# in the app, for example staff-ui/
|
|
362
|
+
npm i ../brand/welcome-back-brand-<version>.tgz
|
|
27
363
|
```
|
|
28
364
|
|
|
29
|
-
|
|
365
|
+
Undo it in the app with `npm i @welcome-back/brand@latest`. Do not commit the
|
|
366
|
+
tarball path in the app's `package.json`.
|
|
30
367
|
|
|
31
|
-
|
|
368
|
+
Prefer `npm pack` to `npm link`. A linked package can load a second copy of
|
|
369
|
+
React, and then hooks fail with "Invalid hook call".
|
|
32
370
|
|
|
33
|
-
|
|
371
|
+
### Common changes
|
|
372
|
+
|
|
373
|
+
| To change | Edit | Note |
|
|
34
374
|
|---|---|---|
|
|
35
|
-
| `
|
|
36
|
-
|
|
|
37
|
-
|
|
|
375
|
+
| Speed | `--wb-runner-step-default` in `src/runnerCss.ts` | Apps can already override it per use with `--wb-runner-step` |
|
|
376
|
+
| Stride length (swing angles) | `@keyframes wb-runner-swing-front` / `-back` in `src/runnerCss.ts` | Angles are measured from each leg drawing's rest pose. The front leg is vertical at `-36deg`, the back leg at `39deg`. Keep forward and back swings equal around those values. |
|
|
377
|
+
| Where the legs join the body | `@keyframes wb-runner-hip-front` / `-back` | Values are in the art's coordinates (the 1500×1500 PDF page) |
|
|
378
|
+
| What is hidden behind the W | `LEGS_CLIP` / `BODY_CLIP` in `src/runnerArt.ts` | See [Source art](#source-art) |
|
|
379
|
+
| A new prop | `src/RunnerLoader.tsx`, plus a test and a row in the props table | |
|
|
380
|
+
| A new asset (logo, icon, token) | A new file in `src/`, exported from `src/index.ts`, plus a test and a README section | |
|
|
381
|
+
|
|
382
|
+
After a visual change, check it in a real app with `npm pack` (above) in light
|
|
383
|
+
mode, dark mode and with reduced motion on.
|
|
384
|
+
|
|
385
|
+
## Publish a change
|
|
386
|
+
|
|
387
|
+
Every change reaches npm through a PR and a tag. Nobody publishes from a laptop,
|
|
388
|
+
and there is no npm token: GitHub Actions publishes with npm trusted publishing.
|
|
389
|
+
|
|
390
|
+
### 1. Pick the version
|
|
391
|
+
|
|
392
|
+
The package follows [semver](https://semver.org). Apps install it with `^`, so
|
|
393
|
+
they get minor and patch releases on their next install.
|
|
394
|
+
|
|
395
|
+
| Change | Bump | Example |
|
|
396
|
+
|---|---|---|
|
|
397
|
+
| Docs, tests, or a fix with no visible change | patch | `0.1.2` → `0.1.3` |
|
|
398
|
+
| A new prop, asset or CSS variable; a visual tweak that keeps the API | minor | `0.1.3` → `0.2.0` |
|
|
399
|
+
| A removed or renamed prop, export or CSS variable | major | `0.9.0` → `1.0.0` |
|
|
400
|
+
|
|
401
|
+
While the version is `0.x`, npm treats a minor bump as breaking for `^`
|
|
402
|
+
ranges. Apps then need an explicit update to get it.
|
|
403
|
+
|
|
404
|
+
### 2. Open a PR with the change and the new version
|
|
405
|
+
|
|
406
|
+
```bash
|
|
407
|
+
git switch main && git pull
|
|
408
|
+
git switch -c <type>/<short-name>
|
|
409
|
+
# make the change
|
|
410
|
+
npm version <patch|minor|major> --no-git-tag-version # edits package.json and package-lock.json
|
|
411
|
+
git commit -am "<type>: <what changed> (v<new version>)"
|
|
412
|
+
git push -u origin HEAD
|
|
413
|
+
gh pr create --base main
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
CI must pass before you merge. Squash-merge the PR.
|
|
417
|
+
|
|
418
|
+
### 3. Tag the merge commit
|
|
419
|
+
|
|
420
|
+
```bash
|
|
421
|
+
git switch main && git pull
|
|
422
|
+
git tag v<new version> # must equal "version" in package.json
|
|
423
|
+
git push origin v<new version>
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
The tag starts the Publish workflow. It:
|
|
427
|
+
|
|
428
|
+
1. checks that the tag equals `version` in `package.json`,
|
|
429
|
+
2. runs typecheck, tests and build (`prepublishOnly`),
|
|
430
|
+
3. publishes to npm through trusted publishing.
|
|
431
|
+
|
|
432
|
+
Watch it with `gh run watch`, or in the repo's **Actions** tab.
|
|
38
433
|
|
|
39
|
-
|
|
40
|
-
`style={{ "--wb-runner-pants": "hsl(var(--background))" }}` on the wrapping element.
|
|
434
|
+
### 4. Check npm and update the apps
|
|
41
435
|
|
|
42
|
-
|
|
436
|
+
```bash
|
|
437
|
+
npm view @welcome-back/brand version # the new version, after a few minutes
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
A new version can take up to about 3 minutes to show on the registry. Then, in
|
|
441
|
+
each app:
|
|
442
|
+
|
|
443
|
+
```bash
|
|
444
|
+
npm i @welcome-back/brand@latest
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
### If the publish fails
|
|
448
|
+
|
|
449
|
+
| Error in the workflow log | Cause | Fix |
|
|
450
|
+
|---|---|---|
|
|
451
|
+
| `Tag must match package.json version` step fails | The tag and `version` differ | Delete the tag (`git push origin :v<x>` and `git tag -d v<x>`), fix the version in a PR, tag again |
|
|
452
|
+
| `403 … OIDC permission denied` | The trusted publisher on npmjs.com does not allow direct publish, or its fields do not match | npmjs.com → package → Settings → Trusted Publisher: `WelcomeBackLoyalty` / `brand` / `publish.yml`, no environment, **Allow npm publish** ticked |
|
|
453
|
+
| `403 … cannot publish over the previously published versions` | That version is already on npm | Bump the version in a new PR and tag again. npm never allows a republish of a version. |
|
|
454
|
+
| Typecheck or test fails | The tagged commit is broken | Fix it in a PR, bump the version, tag again |
|
|
43
455
|
|
|
44
|
-
|
|
456
|
+
To rerun a failed publish without a new tag: `gh run rerun <run-id> --failed`.
|
|
45
457
|
|
|
46
|
-
|
|
47
|
-
2. Tag the merge commit: `git tag v0.2.0 && git push origin v0.2.0`.
|
|
48
|
-
3. The Publish workflow checks the tag against the version, runs typecheck,
|
|
49
|
-
tests and build, and publishes to npm.
|
|
458
|
+
### npm settings (for maintainers)
|
|
50
459
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
460
|
+
- Org: `welcome-back`. Package access: public.
|
|
461
|
+
- Trusted publisher: GitHub Actions, `WelcomeBackLoyalty/brand`, `publish.yml`,
|
|
462
|
+
no environment, **Allow npm publish** ticked.
|
|
463
|
+
- No provenance: npm cannot generate it for a private GitHub repo.
|
|
54
464
|
|
|
55
465
|
## Source art
|
|
56
466
|
|