Skip to content
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

Transcript Front End #11707

Closed
wants to merge 36 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
f187449
Transcript Front End: Initial commit
Isabella-Mitchell Jun 7, 2024
2255797
Transcript - render on local article
Isabella-Mitchell Jun 21, 2024
3929222
Fix errors
Isabella-Mitchell Jul 3, 2024
acdcbe6
Use display: block
Isabella-Mitchell Jul 3, 2024
df49ad1
Transcript-front-end: A11y updates
Isabella-Mitchell Jul 19, 2024
9a11125
Merge branch 'latest' into Transcript-front-end
Isabella-Mitchell Jul 19, 2024
b4c3709
Merge branch 'latest' into Transcript-front-end
Isabella-Mitchell Aug 30, 2024
d68de51
Transcript front end: Adds SVG and makes disclaimer optional
Isabella-Mitchell Aug 30, 2024
af89963
Transcript front end: Updates stories
Isabella-Mitchell Aug 30, 2024
a1a75e1
Transcript front end: Fix unit tests
Isabella-Mitchell Aug 30, 2024
328a686
Transcript-front-end: Replaces svg with css triangle
Isabella-Mitchell Aug 30, 2024
0a7e90a
Transcript front end: tidy
Isabella-Mitchell Aug 30, 2024
0244a53
Transcript front end: Adds initial readme
Isabella-Mitchell Aug 30, 2024
5f0432a
Trancript-front-end: apply darkUi styles
Isabella-Mitchell Aug 30, 2024
4d13863
Replace custom css arrow with SVG
Isabella-Mitchell Sep 13, 2024
10d67a4
Merge branch 'latest' into Transcript-front-end
Isabella-Mitchell Sep 13, 2024
96bf199
Typeify
Isabella-Mitchell Sep 13, 2024
801f9d5
Update mediaLoader to render Transcript if provided
Isabella-Mitchell Sep 13, 2024
7bd1587
Adds unit tests. Updates listItem rendering logic
Isabella-Mitchell Sep 13, 2024
134586a
Add basic transcript tests
Isabella-Mitchell Sep 13, 2024
c9e8ef8
Refines listitem logic and styles
Isabella-Mitchell Sep 13, 2024
317f3a8
Merge branch 'latest' into Transcript-front-end
Isabella-Mitchell Sep 27, 2024
ec0f986
Transcript-front-end: lint post merge
Isabella-Mitchell Sep 27, 2024
f0017a7
Transcript: Update bundle size
Isabella-Mitchell Sep 27, 2024
d493e12
Transcript-front-end: Moves margin
Isabella-Mitchell Sep 27, 2024
dfe8d46
Transcript-front-end: add article with transcript story
Isabella-Mitchell Sep 27, 2024
0d0e6b2
Transcript-front-end: Try fix github alert
Isabella-Mitchell Sep 27, 2024
4167937
Transcript-front-end: SVG align adjust. Tries move visually hidden text
Isabella-Mitchell Sep 27, 2024
b344efc
Transcript-front-end: attempt improve summary text swiping
Isabella-Mitchell Sep 27, 2024
9ff1160
Update snapshot
Isabella-Mitchell Sep 27, 2024
d7b30bb
Transcript-front-end: Mock up Talkback bug fix - introduces bug to Vo…
Isabella-Mitchell Sep 29, 2024
4568711
Transcrip-front-end: Reverts changes. Removes A11y comments
Isabella-Mitchell Sep 29, 2024
157c817
Merge Latest
Isabella-Mitchell Nov 8, 2024
3ac2fcb
WSTEAM1-Transcript: Updates button title and timestamp
Isabella-Mitchell Nov 8, 2024
38c886a
WSTEAM1-Transcript: Updates tests and bundle size
Isabella-Mitchell Nov 8, 2024
14439af
WSTEAM1-Transcript: Renders Transcript on .lite site
Isabella-Mitchell Nov 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,091 changes: 1,091 additions & 0 deletions data/mundo/articles/ce42wzqr2mko-old.json

Large diffs are not rendered by default.

867 changes: 627 additions & 240 deletions data/mundo/articles/ce42wzqr2mko.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions scripts/bundleSize/bundleSizeConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
* We are allowing a variance of -5 on `MIN_SIZE` and +5 on `MAX_SIZE` to avoid the need for frequent changes, as bundle sizes can fluctuate
*/

export const MIN_SIZE = 635 - 5;
export const MAX_SIZE = 1175 + 5;
export const MIN_SIZE = 643 - 5;
export const MAX_SIZE = 1182 + 5;
7 changes: 7 additions & 0 deletions src/app/components/MediaLoader/fixture.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import TranscriptBlock from '../Transcript/fixture.json';

export const aresMediaCaptionBlock = {
id: '31318aec',
type: 'caption',
Expand Down Expand Up @@ -484,6 +486,11 @@ export const aresMediaLiveStreamBlocks = [
aresMediaCaptionBlock,
];

export const aresMediaBlockWithTranscript = [
aresMediaBlock,
aresMediaCaptionBlock,
TranscriptBlock,
];
export const aresMediaBlocks = [aresMediaBlock, aresMediaCaptionBlock];
export const clipMediaBlocks = [livePageClipMediaBlock, livePageCaptionBlock];
export const aresMediaPortraitBlocks = [
Expand Down
19 changes: 19 additions & 0 deletions src/app/components/MediaLoader/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
aresMediaBlocks,
onDemandTvBlocks,
onDemandTvBlocksWithOverrides,
aresMediaBlockWithTranscript,
} from './fixture';
import { MediaBlock } from './types';
import * as buildConfig from './utils/buildSettings';
Expand Down Expand Up @@ -152,6 +153,24 @@ describe('MediaLoader', () => {
);
expect(caption[3]?.textContent).toBe('This is a caption!');
});

it('Displays a transcript when provided ', async () => {
let container;

await act(async () => {
({ container } = render(
<MediaPlayer blocks={aresMediaBlockWithTranscript as MediaBlock[]} />,
{
id: 'testId',
},
));
});

const details = (container as unknown as HTMLElement).querySelector(
'summary',
);
expect(details?.textContent).toContain('Read transcript');
});
});

describe('Metadata', () => {
Expand Down
129 changes: 79 additions & 50 deletions src/app/components/MediaLoader/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import getCaptionBlock from './utils/getCaptionBlock';
import styles from './index.styles';
import { getBootstrapSrc } from '../Ad/Canonical';
import Metadata from './Metadata';
import getTranscriptBlock from './utils/getTranscriptBlock';
import Transcript from '../Transcript';
import AmpMediaLoader from './Amp';

const PAGETYPES_IGNORE_PLACEHOLDER: PageTypes[] = [
Expand Down Expand Up @@ -183,7 +185,11 @@ const MediaLoader = ({ blocks, className, embedded }: Props) => {
!PAGETYPES_IGNORE_PLACEHOLDER.includes(pageType),
);

if (isLite) return null;
// TODO - refactor to improve experience on .lite
const transcriptBlock = getTranscriptBlock(blocks);
const hasTranscript = !!transcriptBlock;

if (isLite && !hasTranscript) return null;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To do: add tests & remove comment


const { model: mediaOverrides } =
filterForBlockType(blocks, 'mediaOverrides') || {};
Expand Down Expand Up @@ -231,59 +237,82 @@ const MediaLoader = ({ blocks, className, embedded }: Props) => {

return (
<>
{
// Prevents the av-embeds route itself rendering the Metadata component
!embedded && (
<Metadata blocks={blocks} embedURL={playerConfig?.externalEmbedUrl} />
)
}
{showPortraitTitle && (
<strong css={styles.titlePortrait}>Watch Moments</strong>
)}
<figure
data-e2e="media-loader__container"
className={className}
css={[
styles.figure(embedded),
playerConfig?.ui?.skin === 'classic' && [
orientation === 'portrait' && styles.portraitFigure(embedded),
orientation === 'landscape' && styles.landscapeFigure,
],
]}
>
{isAmp ? (
<AmpMediaLoader
src={ampIframeUrl}
title={mediaInfo?.title}
placeholderSrc={placeholderSrc}
placeholderSrcset={placeholderSrcset}
noJsMessage={translatedNoJSMessage}
/>
) : (
<>
{showAds && <AdvertTagLoader />}
<BumpLoader />
{hasPlaceholder ? (
<Placeholder
src={placeholderSrc}
srcSet={placeholderSrcset}
{isLite && hasTranscript ? (
<Transcript
transcript={transcriptBlock}
title={placeholderConfig?.mediaInfo?.title}
hideDisclaimer
/>
) : (
<>
{
// Prevents the av-embeds route itself rendering the Metadata component
!embedded && (
<Metadata
blocks={blocks}
embedURL={playerConfig?.externalEmbedUrl}
/>
)
}
{showPortraitTitle && (
<strong css={styles.titlePortrait}>Watch Moments</strong>
)}
<figure
data-e2e="media-loader__container"
className={className}
css={[
styles.figure(embedded),
playerConfig?.ui?.skin === 'classic' && [
orientation === 'portrait' && styles.portraitFigure(embedded),
orientation === 'landscape' && styles.landscapeFigure,
],
]}
>
{isAmp ? (
<AmpMediaLoader
src={ampIframeUrl}
title={mediaInfo?.title}
placeholderSrc={placeholderSrc}
placeholderSrcset={placeholderSrcset}
noJsMessage={translatedNoJSMessage}
mediaInfo={mediaInfo}
onClick={() => setShowPlaceholder(false)}
/>
) : (
<MediaContainer playerConfig={playerConfig} showAds={showAds} />
<>
{showAds && <AdvertTagLoader />}
<BumpLoader />
{hasPlaceholder ? (
<Placeholder
src={placeholderSrc}
srcSet={placeholderSrcset}
noJsMessage={translatedNoJSMessage}
mediaInfo={mediaInfo}
onClick={() => setShowPlaceholder(false)}
/>
) : (
<MediaContainer
playerConfig={playerConfig}
showAds={showAds}
/>
)}
</>
)}
</>
)}
{captionBlock && (
<Caption
block={captionBlock}
type={mediaType}
css={orientation === 'portrait' && styles.captionPortrait}
/>
)}
</figure>
{captionBlock && (
<Caption
block={captionBlock}
type={mediaType}
css={orientation === 'portrait' && styles.captionPortrait}
/>
)}
{transcriptBlock && (
<Transcript
transcript={transcriptBlock}
title={placeholderConfig?.mediaInfo?.title}
hideDisclaimer
/>
)}
</figure>
</>
)}
</>
);
};
Expand Down
3 changes: 2 additions & 1 deletion src/app/components/MediaLoader/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from '#app/models/types/media';
import { OptimoImageBlock } from '#app/models/types/optimo';
import { Translations } from '#app/models/types/translations';
import { TranscriptBlock } from '../Transcript/types';

export type PlayerConfig = {
autoplay?: boolean;
Expand Down Expand Up @@ -151,7 +152,7 @@ export type CaptionBlock = {
export type AresMediaBlock = {
type: 'aresMedia';
model: {
blocks: [AresMediaMetadataBlock | OptimoImageBlock];
blocks: [AresMediaMetadataBlock | OptimoImageBlock | TranscriptBlock];
};
};

Expand Down
20 changes: 20 additions & 0 deletions src/app/components/MediaLoader/utils/getTranscriptBlock.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { aresMediaBlockWithTranscript, aresMediaBlocks } from '../fixture';
import { MediaBlock } from '../types';
import getTranscriptBlock from './getTranscriptBlock';
import TranscriptBlock from '../../Transcript/fixture.json';

describe('getTranscriptBlock', () => {
it('Should return a valid transcript block for an AresMedia block for an article page.', () => {
const result = getTranscriptBlock(
aresMediaBlockWithTranscript as MediaBlock[],
);

expect(result).toStrictEqual(TranscriptBlock);
});

it('Should return null if no transcript block is present.', () => {
const result = getTranscriptBlock(aresMediaBlocks as MediaBlock[]);

expect(result).toStrictEqual(null);
});
});
16 changes: 16 additions & 0 deletions src/app/components/MediaLoader/utils/getTranscriptBlock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import filterForBlockType from '#app/lib/utilities/blockHandlers';
import { MediaBlock } from '../types';
import { TranscriptBlock } from '../../Transcript/types';

export default function getTranscriptBlock(
blocks: MediaBlock[],
): TranscriptBlock | null {
const transcriptBlock: TranscriptBlock = filterForBlockType(
blocks,
'transcript',
);

if (!transcriptBlock) return null;

return transcriptBlock;
}
17 changes: 17 additions & 0 deletions src/app/components/Transcript/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
## Description

The `Transcript` component renders video transcripts.

## Props

| Name | type | Description |
| --------------- | ------- | ----------------------------------------------------- |
| transcript | object | contains transcript content |
| title | string | title of video |
| hideDisclaimer? | boolean | decides whether to show disclaimer (defaults to true) |

## Example

```tsx
<Transcript transcript={transcriptBlock} title={mediaTitle} hideDisclaimer />
```
14 changes: 14 additions & 0 deletions src/app/components/Transcript/TranscriptTimestamp/index.styles.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { css, Theme } from '@emotion/react';

const styles = {
time: ({ mq }: Theme) =>
Isabella-Mitchell marked this conversation as resolved.
Show resolved Hide resolved
css({
float: 'inline-start',
Isabella-Mitchell marked this conversation as resolved.
Show resolved Hide resolved
width: '100%',
[mq.GROUP_1_MIN_WIDTH]: {
width: 'auto',
},
}),
};

export default styles;
10 changes: 10 additions & 0 deletions src/app/components/Transcript/TranscriptTimestamp/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/** @jsx jsx */
import { jsx } from '@emotion/react';
import styles from './index.styles';

// using span not time element to prevent text splitting bug on Talkback
const TranscriptTimestamp = ({ timestamp }: { timestamp: string }) => {
return <span css={styles.time}>{timestamp}</span>;
};

export default TranscriptTimestamp;
Loading
Loading