@supersuit/artifacts 0.30.0 → 0.30.1
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/CHANGELOG.md +13 -0
- package/lib/reader/artifact-reader.js +6 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,19 @@
|
|
|
3
3
|
`@supersuit/artifacts`. One entry per version, newest first. Each entry says what changed, how a
|
|
4
4
|
host can tell whether it is affected (DETECTOR), what a host does about it (REMEDY), and the tests.
|
|
5
5
|
|
|
6
|
+
## 0.30.1
|
|
7
|
+
|
|
8
|
+
**Play from here is one compact pill that stays on screen.** A word tapped near the right edge put
|
|
9
|
+
the bar half off the screen, so its label wrapped to three lines inside a pill inside a pill, with
|
|
10
|
+
an emoji play glyph that iOS draws as a picture.
|
|
11
|
+
|
|
12
|
+
- One pill in the page's accent color, the UI font, 13px, never wrapping, a drawn play triangle, and
|
|
13
|
+
the close button inside the same pill.
|
|
14
|
+
- Placed under the tapped word and clamped inside the screen.
|
|
15
|
+
- DETECTOR: on a phone, pause and tap a word near the right edge. A three-line bubble means 0.30.0.
|
|
16
|
+
- REMEDY: update the dependency.
|
|
17
|
+
- Tests: `artifact-reader-controls.test.tsx` (no emoji, no wrapping, kept inside a 390px screen).
|
|
18
|
+
|
|
6
19
|
## 0.30.0
|
|
7
20
|
|
|
8
21
|
**Every page has a page menu: one small "⋯" button, top right, whose items depend on who you are
|
|
@@ -144,6 +144,8 @@ export function isUserScrollKey(key, target) {
|
|
|
144
144
|
return false;
|
|
145
145
|
return true;
|
|
146
146
|
}
|
|
147
|
+
/** The Play from here bar's width, so it can be kept inside the screen. */
|
|
148
|
+
const OFFER_WIDTH = 168;
|
|
147
149
|
export function ArtifactReader({ src, words, rootId, label, accent, ground, }) {
|
|
148
150
|
const narrator = label;
|
|
149
151
|
const audioRef = useRef(null);
|
|
@@ -184,7 +186,9 @@ export function ArtifactReader({ src, words, rootId, label, accent, ground, }) {
|
|
|
184
186
|
return;
|
|
185
187
|
}
|
|
186
188
|
const r = el.getBoundingClientRect();
|
|
187
|
-
|
|
189
|
+
// Kept on screen: a word near the right edge would push the bar off it and wrap its label.
|
|
190
|
+
const vw = window.innerWidth || document.documentElement.clientWidth || 1024;
|
|
191
|
+
setOffer({ idx, top: r.bottom + window.scrollY + 8, left: Math.max(8, Math.min(r.left, vw - OFFER_WIDTH - 8)) + window.scrollX });
|
|
188
192
|
};
|
|
189
193
|
root.addEventListener('click', onClick);
|
|
190
194
|
return () => root.removeEventListener('click', onClick);
|
|
@@ -264,7 +268,7 @@ export function ArtifactReader({ src, words, rootId, label, accent, ground, }) {
|
|
|
264
268
|
follow(true);
|
|
265
269
|
}, onSeeking: () => {
|
|
266
270
|
startedRef.current = true;
|
|
267
|
-
}, onPause: () => { playingRef.current = false; setPlaying(false); }, onLoadedMetadata: (e) => setDur(e.target.duration), onRateChange: (e) => setRate(e.target.playbackRate) }), offer ? (_jsxs("div", { "data-nospeak": true, className: "absolute z-50 flex items-center
|
|
271
|
+
}, onPause: () => { playingRef.current = false; setPlaying(false); }, onLoadedMetadata: (e) => setDur(e.target.duration), onRateChange: (e) => setRate(e.target.playbackRate) }), offer ? (_jsxs("div", { "data-nospeak": true, "data-play-offer": true, className: "absolute z-50 flex items-center rounded-full font-sans text-[13px] leading-none shadow-lg", style: { top: offer.top, left: offer.left, width: OFFER_WIDTH, whiteSpace: 'nowrap', background: accent, color: ground }, children: [_jsxs("button", { type: "button", "data-play-from-here": true, onClick: () => playFrom(offer.idx), className: "flex flex-1 items-center gap-1.5 rounded-l-full py-2 pl-3 pr-1 font-medium", children: [_jsx("svg", { "aria-hidden": "true", width: "10", height: "11", viewBox: "0 0 10 11", children: _jsx("path", { d: "M1 1l8 4.5L1 10z", fill: "currentColor" }) }), "Play from here"] }), _jsx("button", { type: "button", "aria-label": "Close", onClick: () => setOffer(null), className: "rounded-r-full py-2 pl-1 pr-3 text-base leading-none opacity-70", children: "\u00D7" })] })) : null, playing && !following ? (_jsx("button", { type: "button", "data-follow-voice": true, "data-nospeak": true, onClick: backToVoice, className: "fixed left-1/2 z-50 -translate-x-1/2 rounded-full px-4 py-2 text-sm font-medium shadow-lg", style: { bottom: 'calc(env(safe-area-inset-bottom, 0px) + 5.5rem)', background: accent, color: ground }, children: "Back to the voice" })) : null, _jsx(PlayerBar, { playing: playing, onToggle: toggle, label: narrator, accent: accent, ground: ground, value: t, max: dur, step: 0.1, onSeek: (v) => {
|
|
268
272
|
if (audioRef.current)
|
|
269
273
|
audioRef.current.currentTime = v;
|
|
270
274
|
}, progress: `${fmt(t)} / ${fmt(dur)}`, rate: rate, onRate: () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@supersuit/artifacts",
|
|
3
|
-
"version": "0.30.
|
|
3
|
+
"version": "0.30.1",
|
|
4
4
|
"description": "Publish markdown as branded, read-aloud pages from a Next.js app: the artifacts store, the route factory, the read-along reader, brand packs, password and confidential pages, and share cards.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|