Skip to content
This repository was archived by the owner on Apr 20, 2026. It is now read-only.

Commit c728a1a

Browse files
jkrengeclaude
andauthored
feat: widget enhancements — hidden mode, visibility toggles, i18n, S3 deployment (#3)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 45f28bd commit c728a1a

21 files changed

Lines changed: 630 additions & 203 deletions
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
name: Deploy to prod (release-tag)
2+
3+
on:
4+
release:
5+
types: [published]
6+
7+
jobs:
8+
push_to_s3:
9+
runs-on: ubuntu-latest
10+
permissions:
11+
contents: read
12+
id-token: write
13+
steps:
14+
- name: Checkout
15+
uses: actions/checkout@v6
16+
with:
17+
ref: ${{ github.event.release.tag_name }}
18+
19+
- name: Setup Node
20+
uses: actions/setup-node@v4
21+
with:
22+
node-version: 22
23+
cache: npm
24+
25+
- name: Install dependencies
26+
run: npm ci
27+
28+
- name: Build
29+
run: |
30+
npm run build
31+
npm run build:site
32+
33+
- name: AWS - authentication
34+
uses: aws-actions/configure-aws-credentials@v6
35+
with:
36+
aws-region: eu-central-1
37+
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
38+
39+
- name: Upload versioned files to S3
40+
run: |
41+
aws s3 cp ./dist s3://parcellab-cdn/apps/selection-guide-ui/v1/${{ github.event.release.tag_name }} \
42+
--recursive \
43+
--cache-control max-age=86400
44+
45+
- name: Upload latest plugin files to S3
46+
run: |
47+
aws s3 cp ./dist s3://parcellab-cdn/js/selection-guide-ui/v1 \
48+
--recursive \
49+
--cache-control max-age=86400
50+
51+
- name: Upload demo page to S3
52+
run: |
53+
aws s3 cp ./site s3://parcellab-cdn/apps/selection-guide-ui/v1/demo \
54+
--recursive \
55+
--cache-control max-age=86400
56+
57+
- name: Invalidate CloudFront cache
58+
run: |
59+
aws cloudfront create-invalidation \
60+
--distribution-id E3R5S2BJQI4RDS \
61+
--paths "/js/selection-guide-ui/v1/*" "/apps/selection-guide-ui/v1/*"
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
name: Deploy to staging
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
workflow_dispatch:
8+
9+
env:
10+
NODE_VERSION: 22
11+
12+
jobs:
13+
push_to_s3:
14+
runs-on: ubuntu-latest
15+
permissions:
16+
contents: read
17+
id-token: write
18+
steps:
19+
- name: Checkout
20+
uses: actions/checkout@v6
21+
22+
- name: Setup Node
23+
uses: actions/setup-node@v4
24+
with:
25+
node-version: ${{ env.NODE_VERSION }}
26+
cache: npm
27+
28+
- name: Install dependencies
29+
run: npm ci
30+
31+
- name: Build
32+
run: |
33+
npm run build
34+
npm run build:site
35+
36+
- name: AWS - authentication
37+
uses: aws-actions/configure-aws-credentials@v6
38+
with:
39+
aws-region: eu-central-1
40+
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
41+
42+
- name: Upload to S3
43+
run: |
44+
aws s3 cp ./site s3://parcellab-cdn/playground/selection-guide-ui \
45+
--recursive \
46+
--cache-control max-age=86400
47+
48+
- name: Invalidate CloudFront cache
49+
run: |
50+
aws cloudfront create-invalidation \
51+
--distribution-id E3R5S2BJQI4RDS \
52+
--paths "/playground/selection-guide-ui/*"

.github/workflows/pages.yml

Lines changed: 0 additions & 54 deletions
This file was deleted.

README.md

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Open-source reference implementation of an embeddable size recommendation widget
44

55
Use this widget as-is, or as a starting point for building your own custom integration against the API.
66

7-
**[Live demo](https://parcellab.github.io/selection-guide-ui/)**
7+
**[Live demo](https://cdn.parcellab.com/playground/selection-guide-ui/)**
88

99
**Sample with short info text**
1010

@@ -55,7 +55,7 @@ It ships as a zero-dependency bundle in two formats:
5555
data-not-found-mode="true-to-size"
5656
></div>
5757

58-
<script src="https://parcellab.github.io/selection-guide-ui/dist/size-recommender.iife.js" defer></script>
58+
<script src="https://cdn.parcellab.com/js/selection-guide-ui/v1/size-recommender.iife.js" defer></script>
5959
```
6060

6161
The IIFE build auto-initializes every `[data-size-recommender]` element on the page.
@@ -67,10 +67,15 @@ const widget = window.SizeRecommender.init({
6767
target: '#size-recommender',
6868
accountId: 1617954,
6969
productId: "Men's Iver Pants (tailored fit)",
70+
locale: 'de',
7071
appearance: 'neutral',
7172
density: 'compact',
7273
surface: 'subtle',
7374
notFoundMode: 'true-to-size',
75+
showPill: true,
76+
showScale: true,
77+
showRecommendation: true,
78+
showSummary: true,
7479
className: 'merchant-fit-widget',
7580
theme: {
7681
backgroundColor: '#f6f6f6',
@@ -121,13 +126,17 @@ Full API documentation: [Size Recommender API Reference](https://product-api.par
121126
| `accountId` | `number \| string` || **Required**. parcelLab account identifier. |
122127
| `productId` | `string` || **Required**. Product identifier passed to the API. |
123128
| `articleName` | `string` || Legacy alias for `productId`. Still accepted for backwards compatibility. |
124-
| `locale` | `string` | `'en'` | Locale for default messages. |
129+
| `locale` | `string` | `'en'` | Language for default messages. Supported: `en`, `de`, `fr`, `it`, `es`. |
125130
| `messages` | `Partial<WidgetMessages>` || Override any default message string. |
126-
| `notFoundMode` | `'empty' \| 'true-to-size'` | `'empty'` | Behavior when the API returns 404 (see below). |
131+
| `notFoundMode` | `'empty' \| 'true-to-size' \| 'hidden'` | `'empty'` | Behavior when the API returns 404. `hidden` hides the widget entirely. |
127132
| `apiBaseUrl` | `string` | `'https://product-api.parcellab.com'` | Override the API base URL. |
128133
| `appearance` | `'neutral' \| 'colored'` | `'neutral'` | `neutral` is grayscale; `colored` uses gradient track. |
129134
| `density` | `'compact' \| 'comfortable'` | `'compact'` | `compact` suits PDP sidebars; `comfortable` adds more spacing. |
130135
| `surface` | `'subtle' \| 'plain'` | `'subtle'` | `subtle` renders a light card; `plain` renders inline. |
136+
| `showPill` | `boolean` | `true` | Show or hide the fit category pill badge. |
137+
| `showScale` | `boolean` | `true` | Show or hide the fit position scale bar. |
138+
| `showRecommendation` | `boolean` | `true` | Show or hide the entire recommendation box. |
139+
| `showSummary` | `boolean` | `true` | Show or hide the LLM summary within the recommendation. |
131140
| `className` | `string` || Extra CSS classes added to the root element. |
132141
| `theme` | `Partial<WidgetTheme>` || CSS token overrides (colors, radius, etc.). |
133142

@@ -144,7 +153,11 @@ When using the IIFE auto-init, configure via `data-*` attributes:
144153
data-appearance="colored"
145154
data-density="comfortable"
146155
data-surface="plain"
147-
data-locale="en"
156+
data-locale="de"
157+
data-show-pill="true"
158+
data-show-scale="true"
159+
data-show-recommendation="true"
160+
data-show-summary="false"
148161
data-messages='{"title":"How It Fits"}'
149162
data-theme='{"backgroundColor":"#f6f6f6","radius":"12px"}'
150163
data-class-name="my-custom-class"
@@ -153,10 +166,11 @@ When using the IIFE auto-init, configure via `data-*` attributes:
153166

154167
## 404 Handling
155168

156-
When a product has no recommendation data, the widget supports two modes:
169+
When a product has no recommendation data, the widget supports three modes:
157170

158171
- **`empty`** (default) — shows a "no data available" message
159172
- **`true-to-size`** — renders a "likely true to size" fallback without confidence or summary
173+
- **`hidden`** — hides the widget entirely (`display: none`); the widget reappears when valid data is provided via `update()` or `refresh()`
160174

161175
## Styling
162176

@@ -169,7 +183,7 @@ The widget renders in **light DOM** (not Shadow DOM), so host-page typography in
169183
.pl-size-recommender--{neutral|colored}
170184
.pl-size-recommender--density-{compact|comfortable}
171185
.pl-size-recommender--surface-{subtle|plain}
172-
.pl-size-recommender--state-{loading|ready|fallback-true|empty|error}
186+
.pl-size-recommender--state-{loading|ready|fallback-true|empty|error|hidden}
173187
.pl-size-recommender--fit-{small|true|large|unknown}
174188
```
175189

@@ -266,15 +280,19 @@ npm test
266280

267281
Runs the Vitest test suite with jsdom.
268282

269-
### GitHub Pages
283+
### Deployment
270284

271-
```sh
272-
npm run build:pages
273-
```
285+
The project deploys to S3/CloudFront via GitHub Actions:
286+
287+
- **Staging:** automatically deployed on push to `main` to `s3://parcellab-cdn/playground/selection-guide-ui/`
288+
- **Production:** deployed on GitHub release to `s3://parcellab-cdn/js/selection-guide-ui/v1/` (latest) and `s3://parcellab-cdn/apps/selection-guide-ui/v1/{tag}/` (versioned)
274289

275-
Builds a static demo site to `site/`. The repository is configured to deploy this automatically via GitHub Actions on push to `main`.
290+
Build the demo site locally:
276291

277-
**Demo URL:** [https://parcellab.github.io/selection-guide-ui/](https://parcellab.github.io/selection-guide-ui/)
292+
```sh
293+
npm run build
294+
npm run build:site
295+
```
278296

279297
## Building Your Own
280298

dev/index.html

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,21 @@ <h2 class="text-base font-semibold">Configuration</h2>
112112
/>
113113
</label>
114114

115+
<label class="grid gap-1.5 text-sm font-semibold text-navy-500">
116+
Language
117+
<select
118+
id="locale"
119+
name="locale"
120+
class="field bg-white border border-navy-200 rounded-lg h-11 px-3 text-navy-800 font-normal text-sm"
121+
>
122+
<option value="en">English</option>
123+
<option value="de">Deutsch</option>
124+
<option value="fr">Francais</option>
125+
<option value="it">Italiano</option>
126+
<option value="es">Espanol</option>
127+
</select>
128+
</label>
129+
115130
<label class="grid gap-1.5 text-sm font-semibold text-navy-500">
116131
Missing product
117132
<select
@@ -121,6 +136,7 @@ <h2 class="text-base font-semibold">Configuration</h2>
121136
>
122137
<option value="true-to-size">Show "likely true to size" fallback</option>
123138
<option value="empty">Show empty state</option>
139+
<option value="hidden">Hide widget entirely</option>
124140
</select>
125141
</label>
126142

@@ -132,7 +148,7 @@ <h2 class="text-base font-semibold">Configuration</h2>
132148
class="field bg-white border border-navy-200 rounded-lg h-11 px-3 text-navy-800 font-normal text-sm"
133149
>
134150
<option value="neutral">Neutral</option>
135-
<option value="colored">Colored</option>
151+
<option value="colored" selected>Colored</option>
136152
<option value="alert">Alert</option>
137153
</select>
138154
</label>
@@ -145,7 +161,7 @@ <h2 class="text-base font-semibold">Configuration</h2>
145161
class="field bg-white border border-navy-200 rounded-lg h-11 px-3 text-navy-800 font-normal text-sm"
146162
>
147163
<option value="compact">Compact</option>
148-
<option value="comfortable">Comfortable</option>
164+
<option value="comfortable" selected>Comfortable</option>
149165
</select>
150166
</label>
151167

@@ -157,9 +173,29 @@ <h2 class="text-base font-semibold">Configuration</h2>
157173
class="field bg-white border border-navy-200 rounded-lg h-11 px-3 text-navy-800 font-normal text-sm"
158174
>
159175
<option value="subtle">Subtle card</option>
160-
<option value="plain">Plain inline</option>
176+
<option value="plain" selected>Plain inline</option>
161177
</select>
162178
</label>
179+
180+
<fieldset class="space-y-2">
181+
<legend class="text-xs font-semibold text-navy-500 uppercase tracking-wide">Visibility</legend>
182+
<label class="flex items-center gap-2 text-sm text-navy-700 cursor-pointer">
183+
<input type="checkbox" id="show-pill" checked class="accent-navy-800" />
184+
Show size tag
185+
</label>
186+
<label class="flex items-center gap-2 text-sm text-navy-700 cursor-pointer">
187+
<input type="checkbox" id="show-scale" checked class="accent-navy-800" />
188+
Show scale
189+
</label>
190+
<label class="flex items-center gap-2 text-sm text-navy-700 cursor-pointer">
191+
<input type="checkbox" id="show-recommendation" checked class="accent-navy-800" />
192+
Show recommendation
193+
</label>
194+
<label class="flex items-center gap-2 text-sm text-navy-700 cursor-pointer">
195+
<input type="checkbox" id="show-summary" checked class="accent-navy-800" />
196+
Show summary
197+
</label>
198+
</fieldset>
163199
</div>
164200

165201
<div class="flex flex-wrap gap-3 pt-2">

0 commit comments

Comments
 (0)