-
Notifications
You must be signed in to change notification settings - Fork 0
Feature/arc 3904 video player #150
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
reunefe
wants to merge
12
commits into
master
Choose a base branch
from
feature/ARC-3904_video-player
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
46774cb
ARC-3904: start reworking the flowplayer for custom controls
reunefe 0a00702
ARC-3904: tweak flowplayer and add tests
reunefe 6286c7b
ARC-3904: tweak flowplayer and add tests
reunefe 9f8ee18
ARC-3904: Clean up
reunefe 6400a33
ARC-3904: Fix jumping play/pause overlay
reunefe 8f4626c
ARC-3904: Remove volume flyout and replace to sound on/off
reunefe d154c94
ARC-3904: tweak flowplayer
reunefe 49f651f
ARC-3904: use accent color for icon backgrounds
reunefe 9daf3b7
ARC-3904: Ensure dropdown is not being cut off
reunefe 80ab9a8
ARC-3904: Style option controls like subtitels and speed
reunefe 2d26dac
ARC-3904: Remove subtitle persistence
reunefe 3e96bef
ARC-3904: Make colors a bit more tweakable
reunefe File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
75 changes: 75 additions & 0 deletions
75
src/components/AudioWaveFormDisplay/AudioWaveFormDisplay.helpers.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| export type AudioWaveFormDisplaySize = 'small' | 'large'; | ||
|
|
||
| export interface WaveFormBar { | ||
| x: number; | ||
| y1: number; | ||
| y2: number; | ||
|
reunefe marked this conversation as resolved.
|
||
| } | ||
|
|
||
| // Bar geometry traced from the original design asset. | ||
| const WAVE_FORM_VIEW_BOX_WIDTH = 92; | ||
| const WAVE_FORM_VIEW_BOX_HEIGHT = 44; | ||
| const WAVE_FORM_CENTER_Y = 21.6; | ||
| const WAVE_FORM_FIRST_BAR_X = 0.9; | ||
| const WAVE_FORM_BAR_SPACING = 3; | ||
| export const WAVE_FORM_STROKE_WIDTH = 1.8; | ||
|
|
||
| // Padding around the bars, baked into the viewBox rather than CSS padding so it can't collapse | ||
| // to zero on a short/narrow container. | ||
| const WAVE_FORM_PADDING_X_RATIO = 0.15; | ||
| const WAVE_FORM_PADDING_Y_RATIO = 0.3; | ||
|
|
||
| // Exported so PeakDisplay.tsx can account for this padding in its own clip-path math - otherwise | ||
| // the played/unplayed reveal "plays through" blank space before any bar is visible. | ||
| export const WAVE_FORM_PADDING_X_PERCENT = WAVE_FORM_PADDING_X_RATIO * 100; | ||
|
|
||
| // Half the height of each bar (viewBox units), left to right, traced from the original asset. | ||
| const WAVE_FORM_BAR_HALF_HEIGHTS: readonly number[] = [ | ||
| 0.3, 3.3, 3.3, 6.9, 3.3, 6.9, 13.5, 20.7, 10.5, 6.9, 17.1, 13.5, 10.5, 3.3, 6.9, 3.3, 3.3, 6.9, | ||
| 10.5, 13.5, 6.9, 3.3, 3.3, 6.9, 3.3, 3.3, 6.9, 3.3, 3.3, 1.5, | ||
| ]; | ||
|
|
||
| const WAVE_FORM_BAR_COUNT = WAVE_FORM_BAR_HALF_HEIGHTS.length; | ||
|
|
||
| // Right margin the reference asset leaves after its last bar, reused to size the large viewBox. | ||
| const WAVE_FORM_RIGHT_MARGIN = | ||
| WAVE_FORM_VIEW_BOX_WIDTH - (WAVE_FORM_FIRST_BAR_X + (WAVE_FORM_BAR_COUNT - 1) * WAVE_FORM_BAR_SPACING); | ||
|
|
||
| function buildWaveFormBars(barCount: number, halfHeightAt: (index: number) => number): WaveFormBar[] { | ||
| return Array.from({ length: barCount }, (_, index) => { | ||
| const x = WAVE_FORM_FIRST_BAR_X + index * WAVE_FORM_BAR_SPACING; | ||
| const halfHeight = halfHeightAt(index); | ||
| return { x, y1: WAVE_FORM_CENTER_Y - halfHeight, y2: WAVE_FORM_CENTER_Y + halfHeight }; | ||
| }); | ||
| } | ||
|
|
||
| function getWaveFormViewBoxWidth(barCount: number): number { | ||
| return WAVE_FORM_FIRST_BAR_X + (barCount - 1) * WAVE_FORM_BAR_SPACING + WAVE_FORM_RIGHT_MARGIN; | ||
| } | ||
|
|
||
| const SMALL_WAVE_FORM_BARS: readonly WaveFormBar[] = buildWaveFormBars( | ||
| WAVE_FORM_BAR_COUNT, | ||
| (index) => WAVE_FORM_BAR_HALF_HEIGHTS[index] | ||
| ); | ||
|
|
||
| // Large: the small waveform immediately followed by its own mirror, on one continuous grid. | ||
| const LARGE_WAVE_FORM_BARS: readonly WaveFormBar[] = buildWaveFormBars( | ||
| WAVE_FORM_BAR_COUNT * 2, | ||
| (index) => WAVE_FORM_BAR_HALF_HEIGHTS[index < WAVE_FORM_BAR_COUNT ? index : WAVE_FORM_BAR_COUNT * 2 - 1 - index] | ||
| ); | ||
|
|
||
| export function getWaveFormBars(size: AudioWaveFormDisplaySize): readonly WaveFormBar[] { | ||
| return size === 'large' ? LARGE_WAVE_FORM_BARS : SMALL_WAVE_FORM_BARS; | ||
| } | ||
|
|
||
| // Expands the bars' bounding box to the full display box, per the padding ratios above. | ||
| export function getWaveFormViewBox(size: AudioWaveFormDisplaySize): string { | ||
| const contentWidth = getWaveFormViewBoxWidth(getWaveFormBars(size).length); | ||
| const contentHeight = WAVE_FORM_VIEW_BOX_HEIGHT; | ||
|
|
||
| const width = contentWidth / (1 - 2 * WAVE_FORM_PADDING_X_RATIO); | ||
| const height = contentHeight / (1 - 2 * WAVE_FORM_PADDING_Y_RATIO); | ||
| const minX = -(width - contentWidth) / 2; | ||
| const minY = -(height - contentHeight) / 2; | ||
| return `${minX} ${minY} ${width} ${height}`; | ||
| } | ||
22 changes: 22 additions & 0 deletions
22
src/components/AudioWaveFormDisplay/AudioWaveFormDisplay.scss
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| .c-audio-wave-form-display { | ||
| display: block; | ||
| width: 100%; | ||
| height: 100%; | ||
| background-color: var(--c-audio-wave-form-display-bg, transparent); | ||
|
|
||
| &__scaler { | ||
| display: block; | ||
| width: 100%; | ||
| height: 100%; | ||
| } | ||
|
|
||
| &__svg { | ||
| display: block; | ||
| width: 100%; | ||
| height: 100%; | ||
| } | ||
|
|
||
| &__bar { | ||
| stroke: var(--c-audio-wave-form-display-bar-color, var(--c-audio-wave-form-display-wave-color, #fff)); | ||
| } | ||
| } |
33 changes: 33 additions & 0 deletions
33
src/components/AudioWaveFormDisplay/AudioWaveFormDisplay.stories.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| import type { Meta, StoryObj } from '@storybook/react-vite'; | ||
|
|
||
| import { AudioWaveFormDisplay } from './AudioWaveFormDisplay'; | ||
|
|
||
| const meta: Meta<typeof AudioWaveFormDisplay> = { | ||
| title: 'Components/AudioWaveFormDisplay', | ||
| component: AudioWaveFormDisplay, | ||
| }; | ||
| export default meta; | ||
| type Story = StoryObj<typeof AudioWaveFormDisplay>; | ||
|
|
||
| export const Default: Story = { | ||
| render: () => ( | ||
| <div style={{ display: 'flex', flexDirection: 'column', gap: '1rem', background: '#111', padding: '1rem' }}> | ||
| <div style={{ height: '4rem' }}> | ||
| <AudioWaveFormDisplay ariaLabel="Waveform" size="small" waveColor="#fff" /> | ||
| </div> | ||
| <div style={{ height: '4rem' }}> | ||
| <AudioWaveFormDisplay ariaLabel="Waveform" size="large" waveColor="#00c8aa" /> | ||
| </div> | ||
| </div> | ||
| ), | ||
| args: {}, | ||
| }; | ||
|
|
||
| export const CustomColors: Story = { | ||
| render: () => ( | ||
| <div style={{ height: '4rem' }}> | ||
| <AudioWaveFormDisplay ariaLabel="Waveform" waveColor="#ff6b6b" backgroundColor="#1d1d1d" /> | ||
| </div> | ||
| ), | ||
| args: {}, | ||
| }; |
60 changes: 60 additions & 0 deletions
60
src/components/AudioWaveFormDisplay/AudioWaveFormDisplay.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| import clsx from 'clsx'; | ||
| import { type CSSProperties, type FC, memo } from 'react'; | ||
| import { getWaveFormBars, getWaveFormViewBox, WAVE_FORM_STROKE_WIDTH } from './AudioWaveFormDisplay.helpers'; | ||
| import type { AudioWaveFormDisplayProps } from './AudioWaveFormDisplay.types'; | ||
|
|
||
| import './AudioWaveFormDisplay.scss'; | ||
|
|
||
| // Memoized so PeakDisplay's static "inactive" waveform layer (unchanging colors/size) skips | ||
| // reconciling its ~30-60 <line> elements on every playback timeupdate tick, which only changes | ||
| // the sibling "active" layer's clip-path, not either layer's own props. | ||
| export const AudioWaveFormDisplay: FC<AudioWaveFormDisplayProps> = memo(function AudioWaveFormDisplay({ | ||
| className, | ||
| rootClassName: root = 'c-audio-wave-form-display', | ||
| ariaLabel, | ||
| waveColor, | ||
| backgroundColor, | ||
| size = 'small', | ||
| }) { | ||
| const bars = getWaveFormBars(size); | ||
| const viewBox = getWaveFormViewBox(size); | ||
|
|
||
| return ( | ||
| <div | ||
| role="img" | ||
| aria-label={ariaLabel} | ||
| className={clsx(root, `${root}--${size}`, className)} | ||
| style={ | ||
| { | ||
| '--c-audio-wave-form-display-bg': backgroundColor, | ||
| '--c-audio-wave-form-display-wave-color': waveColor, | ||
| } as CSSProperties | ||
| } | ||
| > | ||
| {/* Plain box for consumers to hook a hover-zoom transform onto: transitioning `transform` | ||
| on an <svg> itself doesn't animate smoothly in every browser, unlike an ordinary element. */} | ||
| <div className="c-audio-wave-form-display__scaler"> | ||
| <svg | ||
| className="c-audio-wave-form-display__svg" | ||
| viewBox={viewBox} | ||
| preserveAspectRatio="xMidYMid meet" | ||
| aria-hidden="true" | ||
| > | ||
| {bars.map((bar, index) => ( | ||
| <line | ||
| // biome-ignore lint/suspicious/noArrayIndexKey: decorative, no identity of its own | ||
| key={index} | ||
| className="c-audio-wave-form-display__bar" | ||
| x1={bar.x} | ||
| x2={bar.x} | ||
| y1={bar.y1} | ||
| y2={bar.y2} | ||
| strokeWidth={WAVE_FORM_STROKE_WIDTH} | ||
| strokeLinecap="round" | ||
| /> | ||
| ))} | ||
| </svg> | ||
| </div> | ||
| </div> | ||
| ); | ||
| }); |
11 changes: 11 additions & 0 deletions
11
src/components/AudioWaveFormDisplay/AudioWaveFormDisplay.types.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| import type { DefaultComponentProps } from '../../types'; | ||
| import type { AudioWaveFormDisplaySize } from './AudioWaveFormDisplay.helpers'; | ||
|
|
||
| export type { AudioWaveFormDisplaySize }; | ||
|
|
||
| export type AudioWaveFormDisplayProps = DefaultComponentProps & { | ||
| waveColor?: string; | ||
| backgroundColor?: string; | ||
| size?: AudioWaveFormDisplaySize; | ||
| ariaLabel?: string; | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| export { AudioWaveFormDisplay } from './AudioWaveFormDisplay'; | ||
| export { WAVE_FORM_PADDING_X_PERCENT } from './AudioWaveFormDisplay.helpers'; | ||
| export * from './AudioWaveFormDisplay.types'; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.