files: the player's −5 s and +5 s buttons, as Ham Share's
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
f2997a04c8
commit
033343793f
@@ -67,6 +67,19 @@ if (await page.locator('canvas.vp-sphere').count()) {
|
|||||||
}
|
}
|
||||||
await page.screenshot({ path: `${SHOTS}/h1-auto.png` })
|
await page.screenshot({ path: `${SHOTS}/h1-auto.png` })
|
||||||
|
|
||||||
|
// The 5-second buttons: back and on, the ball with them.
|
||||||
|
{
|
||||||
|
await controls()
|
||||||
|
const t0 = (await vstate()).t
|
||||||
|
await page.getByRole('button', { name: 'On 5 seconds' }).click()
|
||||||
|
const t1 = (await vstate()).t
|
||||||
|
await page.getByRole('button', { name: 'Back 5 seconds' }).click()
|
||||||
|
await page.getByRole('button', { name: 'Back 5 seconds' }).click()
|
||||||
|
const t2 = (await vstate()).t
|
||||||
|
const ball = await page.evaluate(() => Number(document.querySelector('.vp input[type=range]').value))
|
||||||
|
check('+5 and −5 buttons', t1 - t0 > 4 && t1 - t0 < 6.5 && t1 - t2 > 9 && t1 - t2 < 11 && Math.abs(ball - t2) < 1, `${t0.toFixed(1)} → ${t1.toFixed(1)} → ${t2.toFixed(1)}, ball ${ball.toFixed(1)}`)
|
||||||
|
}
|
||||||
|
|
||||||
const mid = Math.floor(s.d / 2)
|
const mid = Math.floor(s.d / 2)
|
||||||
mark('seek')
|
mark('seek')
|
||||||
await page.evaluate((m) => { document.querySelector('.vp video').currentTime = m }, mid)
|
await page.evaluate((m) => { document.querySelector('.vp video').currentTime = m }, mid)
|
||||||
|
|||||||
+13
-1
@@ -68,6 +68,14 @@ const I = ({ d, size: sz = 20, fill }: { d: string; size?: number; fill?: boolea
|
|||||||
const PLAY = 'M7 4.5v15l12.5-7.5z', PAUSE = 'M8 5v14M16 5v14', CHECK = 'M5 12.5l4.5 4.5L19 7.5', TUNE = 'M4 7h10M18 7h2M4 17h4M12 17h8M16 5v4M10 15v4'
|
const PLAY = 'M7 4.5v15l12.5-7.5z', PAUSE = 'M8 5v14M16 5v14', CHECK = 'M5 12.5l4.5 4.5L19 7.5', TUNE = 'M4 7h10M18 7h2M4 17h4M12 17h8M16 5v4M10 15v4'
|
||||||
const FULL = 'M4 9V4h5M20 9V4h-5M4 15v5h5M20 15v5h-5', SMALL = 'M9 4v5H4M15 4v5h5M9 20v-5H4M15 20v-5h5', PHONE = 'M8 3h8a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H8a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1zM3 9a9 9 0 0 0 0 6M21 9a9 9 0 0 1 0 6'
|
const FULL = 'M4 9V4h5M20 9V4h-5M4 15v5h5M20 15v5h-5', SMALL = 'M9 4v5H4M15 4v5h5M9 20v-5H4M15 20v-5h5', PHONE = 'M8 3h8a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H8a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1zM3 9a9 9 0 0 0 0 6M21 9a9 9 0 0 1 0 6'
|
||||||
|
|
||||||
|
// Five seconds back or on: a circling arrow with the 5 inside.
|
||||||
|
const Skip = ({ back }: { back?: boolean }) => (
|
||||||
|
<svg width={20} height={20} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
|
||||||
|
<path d={back ? 'M12 5a7 7 0 1 1-7 7M12 5l2.5-2.5M12 5l2.5 2.5' : 'M12 5a7 7 0 1 0 7 7M12 5L9.5 2.5M12 5l-2.5 2.5'} />
|
||||||
|
<text x="12" y="15" textAnchor="middle" fontSize="7.5" fontWeight="700" fill="currentColor" stroke="none" fontFamily="system-ui, sans-serif">5</text>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
|
||||||
export default function Player({ path, sudo }: { path: string; sudo: boolean; name: string }) {
|
export default function Player({ path, sudo }: { path: string; sudo: boolean; name: string }) {
|
||||||
const [open, setOpen] = useState<PlayOpen | null>(null)
|
const [open, setOpen] = useState<PlayOpen | null>(null)
|
||||||
const [err, setErr] = useState('')
|
const [err, setErr] = useState('')
|
||||||
@@ -234,7 +242,9 @@ export default function Player({ path, sudo }: { path: string; sudo: boolean; na
|
|||||||
const seekBy = useCallback((d: number) => {
|
const seekBy = useCallback((d: number) => {
|
||||||
const v = video.current
|
const v = video.current
|
||||||
if (!v) return
|
if (!v) return
|
||||||
v.currentTime = Math.max(0, Math.min(info?.duration ?? v.duration, v.currentTime + d))
|
const to = Math.max(0, Math.min(info?.duration ?? v.duration, v.currentTime + d))
|
||||||
|
v.currentTime = to
|
||||||
|
setTime(to) // the ball goes there at once, made yet or not
|
||||||
poke()
|
poke()
|
||||||
}, [info, poke])
|
}, [info, poke])
|
||||||
// Full screen: the browser's where it has one for an element, else (an iPhone) the window.
|
// Full screen: the browser's where it has one for an element, else (an iPhone) the window.
|
||||||
@@ -336,6 +346,8 @@ export default function Player({ path, sudo }: { path: string; sudo: boolean; na
|
|||||||
</div>
|
</div>
|
||||||
<div className="vp-row">
|
<div className="vp-row">
|
||||||
<button className="vp-icon" onClick={toggle} aria-label={paused ? 'Play' : 'Pause'}>{paused ? <I d={PLAY} fill /> : <I d={PAUSE} />}</button>
|
<button className="vp-icon" onClick={toggle} aria-label={paused ? 'Play' : 'Pause'}>{paused ? <I d={PLAY} fill /> : <I d={PAUSE} />}</button>
|
||||||
|
<button className="vp-icon" onClick={() => seekBy(-5)} aria-label="Back 5 seconds" title="Back 5 seconds"><Skip back /></button>
|
||||||
|
<button className="vp-icon" onClick={() => seekBy(5)} aria-label="On 5 seconds" title="On 5 seconds"><Skip /></button>
|
||||||
<span className="vp-time">{clock(shown)} / {clock(dur)}</span>
|
<span className="vp-time">{clock(shown)} / {clock(dur)}</span>
|
||||||
<span className="spacer" />
|
<span className="spacer" />
|
||||||
{vr && canMotion() && (
|
{vr && canMotion() && (
|
||||||
|
|||||||
Reference in New Issue
Block a user