├── .editorconfig ├── .git-blame-ignore-revs ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug.yml │ └── request-for-change.yml ├── PULL_REQUEST_TEMPLATE.md ├── actions │ └── setup-node-env │ │ └── action.yml ├── dependabot.yml ├── labeler.yml └── workflows │ ├── ar-chromatic.yml │ ├── ar-ci.yml │ ├── ar-nodejs.yml │ ├── build-check.yml │ ├── bundle-analyser.yml │ ├── chromatic-label-helper.yml │ ├── cicd.yml │ ├── compress.yml │ ├── container.yml │ ├── dcr-chromatic.yml │ ├── delete-old-packages.yml │ ├── deno.yml │ ├── jest.yml │ ├── labeler.yml │ ├── lighthouse.yml │ ├── lint.yml │ ├── permissions-advisor.yml │ ├── playwright.yml │ ├── prettier.yml │ ├── publish.yml │ ├── scheduled.yml │ ├── schema-check.yml │ ├── stale.yml │ ├── stories-check.yml │ └── typescript.yml ├── .gitignore ├── .husky ├── post-merge ├── pre-commit └── pre-push ├── .npmrc ├── .nvmrc ├── .prettierignore ├── .prettierrc.json ├── .vscode ├── dcr.code-snippets ├── extensions.json ├── settings.json.recommended └── settings.json.required ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── apps-rendering ├── .editorconfig ├── .eslintignore ├── .gitignore ├── .storybook │ ├── fonts-css.ts │ ├── main.js │ ├── mocks │ │ └── jsdom.js │ ├── preview-head.html │ └── preview.js ├── README.md ├── artifact.json ├── assets │ └── fonts │ │ ├── GHGuardianHeadline-Bold.ttf │ │ ├── GHGuardianHeadline-BoldItalic.ttf │ │ ├── GHGuardianHeadline-Light.ttf │ │ ├── GHGuardianHeadline-LightItalic.ttf │ │ ├── GHGuardianHeadline-Medium.ttf │ │ ├── GHGuardianHeadline-MediumItalic.ttf │ │ ├── GHGuardianHeadline-Regular.ttf │ │ ├── GHGuardianHeadline-RegularItalic.ttf │ │ ├── GHGuardianHeadline-Semibold.ttf │ │ ├── GHGuardianHeadline-SemiboldItalic.ttf │ │ ├── GuardianTextEgyptian-Bold.ttf │ │ ├── GuardianTextEgyptian-BoldItalic.ttf │ │ ├── GuardianTextEgyptian-Reg.ttf │ │ ├── GuardianTextEgyptian-RegItalic.ttf │ │ ├── GuardianTextSans-Bold.ttf │ │ ├── GuardianTextSans-BoldItalic.ttf │ │ ├── GuardianTextSans-Regular.ttf │ │ └── GuardianTextSans-RegularItalic.ttf ├── cdk.json ├── cdk │ ├── README.md │ ├── bin │ │ └── cdk.ts │ └── lib │ │ ├── __snapshots__ │ │ └── mobile-apps-rendering.test.ts.snap │ │ ├── mobile-apps-rendering.test.ts │ │ └── mobile-apps-rendering.ts ├── config │ ├── .eslintrc.js │ ├── jest.config.js │ ├── jestSetup.js │ ├── jestglobalSetup.js │ ├── rendered-items-assets-styles.ts │ ├── rendered-items-assets-template.html │ ├── tsconfig.cdk.json │ ├── tsconfig.client.json │ ├── tsconfig.server.json │ └── tsconfig.test.json ├── package.json ├── pull_request_template.md ├── riff-raff.yaml ├── src │ ├── adSlot.stories.tsx │ ├── adSlot.tsx │ ├── ads.test.ts │ ├── ads.ts │ ├── articleFormat.test.ts │ ├── articleFormat.ts │ ├── atoms.test.ts │ ├── atoms.ts │ ├── bodyElement.test.ts │ ├── bodyElement.ts │ ├── bodyElementKind.ts │ ├── campaign.test.ts │ ├── campaign.ts │ ├── capi.test.ts │ ├── capi.ts │ ├── cartoon.test.ts │ ├── cartoon.ts │ ├── client │ │ ├── article.ts │ │ ├── bridgetVersion.ts │ │ ├── callouts.ts │ │ ├── editions.ts │ │ ├── interactives.ts │ │ ├── liveblog.ts │ │ ├── nativeCommunication.ts │ │ ├── newsletterEmbeds.ts │ │ ├── newsletterSignupForm.ts │ │ ├── parser.ts │ │ └── setup.ts │ ├── components │ │ ├── Accordion │ │ │ ├── Accordion.stories.tsx │ │ │ └── index.tsx │ │ ├── Anchor │ │ │ ├── Anchor.stories.tsx │ │ │ └── index.tsx │ │ ├── ArticleBody │ │ │ └── index.tsx │ │ ├── Audio │ │ │ └── index.tsx │ │ ├── Avatar │ │ │ └── index.tsx │ │ ├── Blockquote │ │ │ ├── Blockquote.stories.tsx │ │ │ └── index.tsx │ │ ├── BodyImage │ │ │ ├── BodyImage.defaults.tsx │ │ │ ├── BodyImage.stories.tsx │ │ │ ├── GalleryBodyImage.tsx │ │ │ └── index.tsx │ │ ├── Bullet │ │ │ ├── Bullet.stories.tsx │ │ │ └── index.tsx │ │ ├── Byline │ │ │ ├── AnalysisByline.tsx │ │ │ ├── Byline.defaults.tsx │ │ │ ├── Byline.stories.tsx │ │ │ ├── CommentByline.tsx │ │ │ ├── DeadBlogByline.tsx │ │ │ ├── GalleryByline.tsx │ │ │ ├── LabsByline.tsx │ │ │ ├── LiveBlogByline.tsx │ │ │ └── index.tsx │ │ ├── BylineCard │ │ │ └── index.tsx │ │ ├── Callout │ │ │ ├── Callout.stories.tsx │ │ │ ├── callout.test.ts │ │ │ ├── calloutBlock.tsx │ │ │ ├── calloutComponents.tsx │ │ │ ├── calloutContact.tsx │ │ │ ├── calloutForm.tsx │ │ │ ├── formFields.tsx │ │ │ ├── index.tsx │ │ │ ├── shareLink.tsx │ │ │ ├── styles.ts │ │ │ └── theme.ts │ │ ├── CaptionIcon │ │ │ ├── CaptionIcon.stories.tsx │ │ │ └── index.tsx │ │ ├── Card │ │ │ └── index.tsx │ │ ├── CheckboxInput │ │ │ └── index.tsx │ │ ├── ClickToView │ │ │ ├── ClickToView.test.tsx │ │ │ └── index.tsx │ │ ├── CommentCount │ │ │ ├── CommentCount.stories.tsx │ │ │ └── index.tsx │ │ ├── Credit │ │ │ └── index.tsx │ │ ├── Cutout │ │ │ └── index.tsx │ │ ├── Dateline │ │ │ ├── Dateline.stories.tsx │ │ │ └── index.tsx │ │ ├── Deadline │ │ │ ├── index.test.ts │ │ │ ├── index.tsx │ │ │ └── styles.ts │ │ ├── DesignTag │ │ │ ├── DesignTag.stories.tsx │ │ │ └── index.tsx │ │ ├── EmailSignup │ │ │ └── index.tsx │ │ ├── EmailSignupForm │ │ │ └── index.tsx │ │ ├── Embed │ │ │ └── index.tsx │ │ ├── EmbedWrapper │ │ │ ├── EmbedWrapper.stories.tsx │ │ │ ├── EmbedWrapper.test.tsx │ │ │ └── index.tsx │ │ ├── Epic │ │ │ └── index.tsx │ │ ├── EpicContent │ │ │ └── index.tsx │ │ ├── FigCaption │ │ │ ├── FigCaption.stories.tsx │ │ │ └── index.tsx │ │ ├── FirstPublished │ │ │ ├── FirstPublished.stories.tsx │ │ │ └── index.tsx │ │ ├── Follow │ │ │ ├── Follow.stories.tsx │ │ │ ├── Follow.test.tsx │ │ │ └── index.tsx │ │ ├── FollowStatus │ │ │ └── index.tsx │ │ ├── FootballScores │ │ │ ├── FootballScores.stories.tsx │ │ │ └── index.tsx │ │ ├── Footer │ │ │ ├── Footer.defaults.tsx │ │ │ ├── Footer.stories.tsx │ │ │ ├── GalleryFooter.tsx │ │ │ ├── ImmersiveFooter.tsx │ │ │ └── index.tsx │ │ ├── FooterContent │ │ │ └── index.tsx │ │ ├── GenericEmbed │ │ │ └── index.tsx │ │ ├── GridItem │ │ │ └── index.tsx │ │ ├── HeadingTwo │ │ │ ├── HeadingTwo.defaults.tsx │ │ │ ├── ImmersiveHeadingTwo.tsx │ │ │ ├── LabsHeadingTwo.tsx │ │ │ └── index.tsx │ │ ├── Headline │ │ │ ├── BlogHeadline.tsx │ │ │ ├── CommentHeadline.tsx │ │ │ ├── FeatureHeadline.tsx │ │ │ ├── GalleryHeadline.tsx │ │ │ ├── Headline.defaults.tsx │ │ │ ├── Headline.stories.tsx │ │ │ ├── ImmersiveHeadline.tsx │ │ │ ├── InterviewHeadline.tsx │ │ │ ├── LabsHeadline.tsx │ │ │ ├── MediaHeadline.tsx │ │ │ ├── ReviewHeadline.tsx │ │ │ └── index.tsx │ │ ├── HeadlineByline │ │ │ ├── HeadlineByline.stories.tsx │ │ │ └── index.tsx │ │ ├── HorizontalRule │ │ │ ├── HorizontalRule.stories.tsx │ │ │ └── index.tsx │ │ ├── Img │ │ │ └── index.tsx │ │ ├── ImgAlt │ │ │ ├── ImgAlt.stories.tsx │ │ │ └── index.tsx │ │ ├── InPageNewsletterSignup │ │ │ ├── InPageNewsletterSignup.stories.tsx │ │ │ ├── NotSupportedMessage.tsx │ │ │ └── index.tsx │ │ ├── InlineSkipToWrapper │ │ │ └── index.tsx │ │ ├── Instagram │ │ │ └── index.tsx │ │ ├── Interactive │ │ │ └── index.tsx │ │ ├── InteractiveAtom │ │ │ └── index.tsx │ │ ├── KeyEvents │ │ │ ├── KeyEvents.stories.tsx │ │ │ └── index.tsx │ │ ├── Kicker │ │ │ └── index.tsx │ │ ├── LabsLogo │ │ │ └── index.tsx │ │ ├── LastUpdated │ │ │ ├── LastUpdated.stories.tsx │ │ │ └── index.tsx │ │ ├── Layout │ │ │ ├── AnalysisLayout.tsx │ │ │ ├── CommentLayout.tsx │ │ │ ├── GalleryLayout.tsx │ │ │ ├── ImmersiveLayout.tsx │ │ │ ├── InteractiveLayout.tsx │ │ │ ├── LabsLayout.tsx │ │ │ ├── Layout.stories.tsx │ │ │ ├── LetterLayout.tsx │ │ │ ├── LiveLayout.tsx │ │ │ ├── NewsletterSignUpLayout.tsx │ │ │ ├── StandardLayout.tsx │ │ │ └── index.tsx │ │ ├── List │ │ │ ├── List.stories.tsx │ │ │ └── index.tsx │ │ ├── ListItem │ │ │ ├── ListItem.stories.tsx │ │ │ └── index.tsx │ │ ├── LiveBlock │ │ │ └── index.tsx │ │ ├── LiveBlockContainer │ │ │ └── index.tsx │ │ ├── LiveBlocks │ │ │ └── index.tsx │ │ ├── LiveDateline │ │ │ └── index.tsx │ │ ├── LiveEventLink │ │ │ └── index.tsx │ │ ├── LiveblogHeader │ │ │ └── index.tsx │ │ ├── LiveblogMetadataLines │ │ │ └── index.tsx │ │ ├── Logo │ │ │ ├── Logo.stories.tsx │ │ │ ├── Logo.test.tsx │ │ │ └── index.tsx │ │ ├── MainMedia │ │ │ ├── GalleryCaption.tsx │ │ │ ├── ImmersiveCaption.tsx │ │ │ ├── MainMedia.defaults.ts │ │ │ ├── MainMediaImage │ │ │ │ ├── BlogMainMediaImage.tsx │ │ │ │ ├── CommentMainMediaImage.tsx │ │ │ │ ├── GalleryMainMediaImage.tsx │ │ │ │ ├── ImmersiveMainMediaImage.tsx │ │ │ │ ├── InterviewMainMediaImage.tsx │ │ │ │ ├── MainMediaImage.defaults.tsx │ │ │ │ ├── NewsletterSignupMainMediaImage.tsx │ │ │ │ └── index.tsx │ │ │ ├── MainMediaVideo │ │ │ │ └── index.tsx │ │ │ └── index.tsx │ │ ├── MainMediaCaption │ │ │ ├── Caption.tsx │ │ │ ├── MainMediaCaption.defaults.tsx │ │ │ ├── MainMediaCaption.stories.tsx │ │ │ ├── MainMediaCaption.test.tsx │ │ │ └── index.tsx │ │ ├── MatchStatusIcon │ │ │ └── index.tsx │ │ ├── Meta │ │ │ └── index.tsx │ │ ├── Metadata │ │ │ ├── ExtendedMetadata.tsx │ │ │ ├── GalleryMetadata.tsx │ │ │ ├── ImmersiveMetadata.tsx │ │ │ ├── LiveBlogMetadata.tsx │ │ │ ├── Metadata.defaults.tsx │ │ │ ├── Metadata.stories.tsx │ │ │ ├── ShortMetadata.tsx │ │ │ └── index.tsx │ │ ├── NewsletterSignup │ │ │ ├── NewsletterSignup.stories.tsx │ │ │ ├── PrivacyWording.tsx │ │ │ └── index.tsx │ │ ├── OrderedList │ │ │ ├── OrderedList.stories.tsx │ │ │ └── index.tsx │ │ ├── Pagination │ │ │ ├── Pagination.stories.tsx │ │ │ └── index.tsx │ │ ├── Paragraph │ │ │ ├── Paragraph.stories.tsx │ │ │ └── index.tsx │ │ ├── PinnedPost │ │ │ ├── PinnedPost.stories.tsx │ │ │ └── index.tsx │ │ ├── Pullquote │ │ │ ├── Pullquote.stories.tsx │ │ │ └── index.tsx │ │ ├── RadioInput │ │ │ └── index.tsx │ │ ├── RelatedContent │ │ │ ├── GalleryRelatedContent.tsx │ │ │ ├── ImmersiveRelatedContent.tsx │ │ │ ├── RelatedContent.defaults.tsx │ │ │ └── index.tsx │ │ ├── RichLink │ │ │ ├── RichLink.stories.tsx │ │ │ └── index.tsx │ │ ├── Scripts │ │ │ └── index.tsx │ │ ├── Series │ │ │ ├── GallerySeries.tsx │ │ │ ├── ImmersiveSeries.tsx │ │ │ ├── Series.stories.tsx │ │ │ └── index.tsx │ │ ├── SpecialReportAltAtom │ │ │ ├── SpecialReportAltAtom.stories.tsx │ │ │ └── index.tsx │ │ ├── Standfirst │ │ │ ├── AnalysisStandfirst.tsx │ │ │ ├── DeadBlogStandfirst.tsx │ │ │ ├── ExplainerStandfirst.tsx │ │ │ ├── GalleryStandfirst.tsx │ │ │ ├── ImmersiveLabsStandfirst.tsx │ │ │ ├── ImmersiveStandfirst.tsx │ │ │ ├── InterviewStandfirst.tsx │ │ │ ├── LabsStandfirst.tsx │ │ │ ├── LiveBlogStandfirst.tsx │ │ │ ├── MediaStandfirst.tsx │ │ │ ├── NewsletterSignupStandfirst.tsx │ │ │ ├── ReviewStandfirst.tsx │ │ │ ├── Standfirst.defaults.tsx │ │ │ ├── Standfirst.stories.tsx │ │ │ └── index.tsx │ │ ├── StarRating │ │ │ ├── StarRating.stories.tsx │ │ │ └── index.tsx │ │ ├── TableOfContents │ │ │ ├── TableOfContents.stories.tsx │ │ │ └── index.tsx │ │ ├── Tags │ │ │ ├── GalleryTags.tsx │ │ │ ├── ImmersiveTags.tsx │ │ │ ├── Tags.defaults.tsx │ │ │ ├── Tags.stories.tsx │ │ │ ├── Tags.test.tsx │ │ │ └── index.tsx │ │ ├── TeamScore │ │ │ └── index.tsx │ │ ├── Video │ │ │ └── index.tsx │ │ ├── WithAgeWarning │ │ │ ├── WithAgeWarning.test.tsx │ │ │ └── index.tsx │ │ ├── caption │ │ │ ├── caption.tsx │ │ │ └── index.tsx │ │ ├── editions │ │ │ ├── avatar │ │ │ │ ├── avatar.stories.tsx │ │ │ │ └── index.tsx │ │ │ ├── byline │ │ │ │ ├── byline.stories.tsx │ │ │ │ └── index.tsx │ │ │ ├── cartoon │ │ │ │ ├── cartoon.stories.tsx │ │ │ │ └── index.tsx │ │ │ ├── footballScores │ │ │ │ ├── footballScores.stories.tsx │ │ │ │ └── index.tsx │ │ │ ├── galleryImage │ │ │ │ ├── galleryImage.stories.tsx │ │ │ │ └── index.tsx │ │ │ ├── header │ │ │ │ └── index.tsx │ │ │ ├── headerImageCaption.tsx │ │ │ ├── headerMedia │ │ │ │ ├── headerMedia.stories.tsx │ │ │ │ └── index.tsx │ │ │ ├── headline │ │ │ │ ├── headline.stories.tsx │ │ │ │ └── index.tsx │ │ │ ├── kickerPicker.ts │ │ │ ├── layout │ │ │ │ ├── index.tsx │ │ │ │ └── layout.stories.tsx │ │ │ ├── lines.tsx │ │ │ ├── pullquote │ │ │ │ ├── index.tsx │ │ │ │ └── pullquote.stories.tsx │ │ │ ├── series │ │ │ │ ├── index.tsx │ │ │ │ └── series.stories.tsx │ │ │ ├── shareIcon │ │ │ │ ├── index.tsx │ │ │ │ └── shareIcon.stories.tsx │ │ │ ├── standfirst │ │ │ │ ├── index.tsx │ │ │ │ └── standfirst.stories.tsx │ │ │ ├── starRating │ │ │ │ ├── index.tsx │ │ │ │ └── starRating.stories.tsx │ │ │ ├── styles.ts │ │ │ ├── teamScore │ │ │ │ └── index.tsx │ │ │ ├── utils │ │ │ │ └── useOnlineStatus.tsx │ │ │ └── video │ │ │ │ ├── index.tsx │ │ │ │ └── video.stories.tsx │ │ └── media │ │ │ ├── articleBody.tsx │ │ │ ├── articleSeries.tsx │ │ │ ├── byline.tsx │ │ │ └── tags.tsx │ ├── contributer.test.ts │ ├── contributor.ts │ ├── date.test.ts │ ├── date.ts │ ├── datetime.ts │ ├── embed.ts │ ├── fixtures │ │ ├── article.ts │ │ ├── campaign.ts │ │ ├── cartoon.ts │ │ ├── galleryBody.ts │ │ ├── galleryImage.ts │ │ ├── image.ts │ │ ├── item.ts │ │ ├── live.ts │ │ ├── newsletterSignUpContent.ts │ │ └── relatedContent.ts │ ├── football.ts │ ├── grid │ │ ├── LeftCentreBorder.tsx │ │ └── grid.ts │ ├── helperTest.ts │ ├── image.test.ts │ ├── image.ts │ ├── image │ │ ├── __snapshots__ │ │ │ └── sizes.test.tsx.snap │ │ ├── image.ts │ │ ├── lightbox.ts │ │ ├── sizes.test.tsx │ │ ├── sizes.ts │ │ ├── srcsets.test.ts │ │ └── srcsets.ts │ ├── item.test.ts │ ├── item.ts │ ├── lib.test.tsx │ ├── lib.ts │ ├── liveBlock.ts │ ├── logger │ │ ├── LoggerFunctions.ts │ │ ├── clientDev │ │ │ └── index.ts │ │ ├── clientProd │ │ │ └── index.ts │ │ ├── index.ts │ │ └── server │ │ │ └── index.ts │ ├── mainMedia.ts │ ├── native │ │ ├── nativeApi.ts │ │ └── thrift │ │ │ ├── nativeConnection.ts │ │ │ └── protocols.ts │ ├── newsletter.test.ts │ ├── newsletter.ts │ ├── optional.ts │ ├── outline.test.ts │ ├── outline.ts │ ├── pagination.test.ts │ ├── pagination.ts │ ├── palette │ │ ├── background.ts │ │ ├── border.ts │ │ ├── colour.ts │ │ ├── fill.ts │ │ ├── hover.ts │ │ ├── index.ts │ │ └── text.ts │ ├── parser.md │ ├── parser.test.ts │ ├── parser.ts │ ├── parserContext.ts │ ├── quizAtom.ts │ ├── relatedContent.test.ts │ ├── relatedContent.ts │ ├── renderer.test.ts │ ├── renderer.ts │ ├── result.test.ts │ ├── result.ts │ ├── server │ │ ├── appIdentity.ts │ │ ├── assets.ts │ │ ├── aws.ts │ │ ├── csp.test.ts │ │ ├── csp.ts │ │ ├── decoders.ts │ │ ├── editionsPage.tsx │ │ ├── footballContent.ts │ │ ├── page.tsx │ │ ├── paramParser.ts │ │ ├── server.ts │ │ └── ssmConfig.ts │ ├── span.test.ts │ ├── span.ts │ ├── styles.test.ts │ ├── styles.ts │ ├── testsHelper.ts │ ├── video.test.ts │ └── video.ts ├── tsconfig.json ├── vendor │ └── @guardian │ │ └── types │ │ ├── README.md │ │ ├── index.d.ts │ │ ├── index.js │ │ ├── option.d.ts │ │ ├── option.js │ │ ├── result.d.ts │ │ └── result.js └── webpack.config.ts ├── dotcom-rendering ├── .eslintignore ├── .eslintrc.js ├── .fast ├── .gitignore ├── .prout.json ├── .storybook │ ├── decorators │ │ ├── configContextDecorator.tsx │ │ ├── gridDecorators.tsx │ │ ├── splitThemeDecorator.tsx │ │ └── themeDecorator.tsx │ ├── main.ts │ ├── mocks │ │ ├── bridgetApi.ts │ │ ├── jsdom.ts │ │ ├── log4js.ts │ │ └── paletteDeclarations.ts │ ├── modes.ts │ ├── preview-head.html │ ├── preview.ts │ └── toolbar │ │ └── globalColourScheme.ts ├── Containerfile ├── README.md ├── __mocks__ │ └── svgMock.tsx ├── cdk.json ├── cdk │ ├── bin │ │ └── cdk.ts │ └── lib │ │ ├── __snapshots__ │ │ └── renderingStack.test.ts.snap │ │ ├── renderingStack.test.ts │ │ ├── renderingStack.ts │ │ └── userData.ts ├── configs │ └── webpack │ │ ├── .test.mjs │ │ ├── README.md │ │ ├── base.mjs │ │ ├── client.apps.mjs │ │ ├── client.web.mjs │ │ ├── client.web.variant.mjs │ │ ├── server.dev.mjs │ │ ├── server.mjs │ │ └── utils │ │ └── env.mjs ├── docs │ ├── ads │ │ ├── apps-ads.md │ │ └── web-ads.md │ ├── architecture │ │ ├── 000-architecture-decision-records.md │ │ ├── 001-dotcom-rendering.md │ │ ├── 002-componentisation.md │ │ ├── 003-react.md │ │ ├── 004-emotion.md │ │ ├── 005-monorepo.md │ │ ├── 006-support-for-frontend-only.md │ │ ├── 007-css-in-js.md │ │ ├── 008-static-types.md │ │ ├── 009-storybook.md │ │ ├── 010-capi-elements-as-components.md │ │ ├── 011-amp.md │ │ ├── 012-new-elements-models-in-frontend.md │ │ ├── 013-testing.md │ │ ├── 014-client-side-computation.md │ │ ├── 015-javascript-loading.md │ │ ├── 017-remove-monorepo.md │ │ ├── 018-react-hooks.md │ │ ├── 019-react-to-preact.md │ │ ├── 020-react-portals.md │ │ ├── 021-NoJS-navigation-and-accessibility.md │ │ ├── 022-dynamic-imports.md │ │ ├── 023-script-loading.md │ │ ├── 024-click-to-view.md │ │ ├── 025-interactive-pressing.md │ │ ├── 026-better-partial-hydration.md │ │ ├── 027-pictures.md │ │ ├── 028-react-context-api.md │ │ ├── 029-scaling-policy-decision-record.md │ │ ├── 3rd-party-technical-review │ │ │ ├── 000-technical-review-records.md │ │ │ ├── 001-modi-poc.md │ │ │ ├── 002-ipsos-mori.md │ │ │ ├── 003-gracenote.md │ │ │ └── 004-urlbox.md │ │ ├── amp │ │ │ └── 000-structure-for-initial-milestone.md │ │ ├── historic-adrs │ │ │ ├── 016-react-context-api.md │ │ │ ├── dotenv.md │ │ │ ├── multiple-sites.md │ │ │ ├── signing-image-urls.md │ │ │ └── use-percy-for-e2e-visual-regression-testing.md │ │ └── proposed-adrs │ │ │ └── rendering-type.md │ ├── commercial │ │ ├── liveblog-server-side-ad-slots.md │ │ └── overview.md │ ├── contracts │ │ ├── 000-contracts.md │ │ ├── 001-commercial-selectors.md │ │ ├── 002-viewer-body-selector.md │ │ ├── 003-extra-classes-for-interactives.md │ │ └── 004-heatphan-selectors.md │ ├── contributing │ │ ├── README.md │ │ ├── code-style.md │ │ ├── detailed-setup-guide-pics │ │ │ └── high-level-diagram.png │ │ ├── detailed-setup-guide.md │ │ ├── how-to.md │ │ └── where-should-my-code-live.md │ ├── development │ │ ├── ab-testing-in-dcr.md │ │ ├── apps-testing.md │ │ ├── assets │ │ │ ├── android-clear-cache.png │ │ │ ├── local-ar-android.png │ │ │ └── local-ar-ios.png │ │ ├── loadable-components.md │ │ ├── local-sign-in.md │ │ ├── run-prod-bundle-locally.md │ │ ├── storybook.md │ │ └── track-user-behaviour.md │ ├── duplication.md │ ├── elements │ │ ├── Disclaimer.md │ │ ├── Embed.md │ │ ├── Image.md │ │ ├── Instagram.md │ │ ├── Richlink.md │ │ ├── Subheading.md │ │ ├── Text.md │ │ └── Tweet.md │ ├── email-newsletters-page.md │ ├── images │ │ ├── logo-ab-testing.png │ │ ├── logo-chromatic.jpg │ │ ├── logo-deno.svg │ │ ├── logo-emotion.png │ │ ├── logo-express.png │ │ ├── logo-jest.jpg │ │ ├── logo-playwright.svg │ │ ├── logo-preact.jpg │ │ ├── logo-storybook.jpg │ │ └── logo-typescript.png │ ├── incidents │ │ └── incident-handling.md │ ├── interactives │ │ └── working-with-interactives.md │ ├── lightbox.md │ ├── logging.md │ ├── patterns │ │ ├── decide-layout.md │ │ ├── enhancers.md │ │ └── switch-on-display-design.md │ ├── principles │ │ ├── browser-support.md │ │ ├── developer-experience.md │ │ ├── images │ │ │ ├── chrome70.png │ │ │ └── ie8.png │ │ └── performance-budgets.md │ ├── resources.md │ ├── testing.md │ ├── tracking │ │ └── 001-sentry.md │ ├── values │ │ └── README.md │ └── youtube │ │ ├── youtube-variations-2020-06-23.md │ │ ├── youtube-variations-2021-11-17.md │ │ ├── youtubeimages-2020 │ │ ├── embedcapijson.png │ │ ├── embedcomposerscreenshot.png │ │ ├── embeddcrjson.png │ │ ├── embedscreenshot.png │ │ ├── mediaatomcapijson.png │ │ ├── mediaatomcomposerscreenshot.png │ │ ├── mediaatomdcrjson.png │ │ ├── mediaatomscreenshot.png │ │ ├── structuredataembedscreenshot.png │ │ ├── structureddataembedcapijson.png │ │ └── structureddataembedcomposer.png │ │ └── youtubeimages-2021 │ │ ├── composer-embed-dialog.png │ │ ├── composer-embed-menu.png │ │ ├── composer-generic-embed-code.png │ │ ├── composer-video-menu.png │ │ ├── composer-youtube-embed-atom.png │ │ ├── composer-youtube-embed-generic.png │ │ └── composer-youtube-embed.png ├── fixtures │ ├── config-overrides.js │ ├── config.js │ ├── generated │ │ ├── cricket-match.ts │ │ ├── fe-articles │ │ │ ├── Analysis.ts │ │ │ ├── Audio.ts │ │ │ ├── Comment.ts │ │ │ ├── Dead.ts │ │ │ ├── Editorial.ts │ │ │ ├── Explainer.ts │ │ │ ├── Feature.ts │ │ │ ├── Gallery.ts │ │ │ ├── Interview.ts │ │ │ ├── Labs.ts │ │ │ ├── Letter.ts │ │ │ ├── Live.ts │ │ │ ├── LiveBlogSingleContributor.ts │ │ │ ├── MatchReport.ts │ │ │ ├── NewsletterSignup.ts │ │ │ ├── NumberedList.ts │ │ │ ├── PhotoEssay.ts │ │ │ ├── Picture.ts │ │ │ ├── Quiz.ts │ │ │ ├── Recipe.ts │ │ │ ├── Review.ts │ │ │ ├── SpecialReport.ts │ │ │ ├── Standard.ts │ │ │ ├── StandardWithVideo.ts │ │ │ └── Video.ts │ │ ├── football-live.ts │ │ ├── images.ts │ │ ├── match-report.ts │ │ ├── series.ts │ │ └── story-package.ts │ ├── manual │ │ ├── InteractiveAtomBlockElement.ts │ │ ├── InteractiveLayoutAtom.ts │ │ ├── block-meta-data.ts │ │ ├── calloutCampaign.ts │ │ ├── calloutCampaignV2.ts │ │ ├── chartAtoms.ts │ │ ├── comment.ts │ │ ├── contributionsHeader.ts │ │ ├── cricket-scoreboard.ts │ │ ├── discussion-no-top-comments.ts │ │ ├── discussion.ts │ │ ├── discussionApiUrl.ts │ │ ├── discussionWithNoComments.ts │ │ ├── discussionWithTwoComments.ts │ │ ├── editionsCrossword.ts │ │ ├── ensure.ts │ │ ├── footballData.ts │ │ ├── footballMatches.ts │ │ ├── frontCollections.ts │ │ ├── guideAtom.ts │ │ ├── highlights-trails.ts │ │ ├── key-events.ts │ │ ├── knowledgeQuizAtom.ts │ │ ├── legacyDiscussionWithoutThreading.ts │ │ ├── live-blog-key-events.ts │ │ ├── liveBlock.ts │ │ ├── most-read-geo.ts │ │ ├── most-read.ts │ │ ├── nav-international.ts │ │ ├── nav-world.ts │ │ ├── noTopPicks.ts │ │ ├── personalityQuizAtom.ts │ │ ├── qandaAtom.tsx │ │ ├── related.ts │ │ ├── short-discussion.ts │ │ ├── show-more-trails.ts │ │ ├── timelineAtom.tsx │ │ ├── topPicks.ts │ │ ├── trails-nav.ts │ │ └── trails.ts │ └── switch-overrides.js ├── index.d.ts ├── jest.config.js ├── lighthouserc.js ├── makefile ├── package.json ├── playwright.config.ts ├── playwright │ ├── fixtures │ │ ├── cricket-match.js │ │ └── tweet-block.js │ ├── lib │ │ ├── cmp.ts │ │ ├── cookies.ts │ │ ├── iframe.ts │ │ ├── islands.ts │ │ ├── load-page.ts │ │ ├── locators.ts │ │ ├── network.ts │ │ └── ophan.ts │ └── tests │ │ ├── article.e2e.spec.ts │ │ ├── article.embeds.e2e.spec.ts │ │ ├── article.interactivity.e2e.spec.ts │ │ ├── article.metaAndOphan.e2e.spec.ts │ │ ├── atom.interactivity.e2e.spec.ts │ │ ├── atom.video.e2e.spec.ts │ │ ├── banner.e2e.spec.ts │ │ ├── commercial.e2e.spec.ts │ │ ├── edition-switcher-banner.e2e.spec.ts │ │ ├── epic.interactivity.e2e.spec.ts │ │ ├── lightbox.e2e.spec.ts │ │ ├── liveblog.interactivity.e2e.spec.ts │ │ ├── ophan.e2e.spec.ts │ │ ├── paid.content.e2e.spec.ts │ │ └── signedin.e2e.spec.ts ├── scripts │ ├── check-node-versions.mjs │ ├── deploy │ │ ├── build-riffraff-bundle.mjs │ │ └── riff-raff.yaml │ ├── env │ │ ├── check-deps.js │ │ └── check-files.js │ ├── gen-stories │ │ ├── check-stories.mjs │ │ ├── gen-stories.mjs │ │ └── get-stories.mjs │ ├── islands │ │ ├── island-descriptions.mjs │ │ └── islands.html │ ├── jest │ │ └── setup.ts │ ├── jsonSchema │ │ ├── checkSchemas.mjs │ │ ├── genSchemas.mjs │ │ └── schema.mjs │ ├── lighthouse │ │ └── puppeteer-script.js │ ├── nginx │ │ ├── Brewfile │ │ ├── nginx-mappings.yaml │ │ └── setup.sh │ ├── perf │ │ ├── gc │ │ │ └── gc-report.js │ │ └── k6 │ │ │ ├── README.md │ │ │ ├── article-nier-automata.json │ │ │ ├── k6-install.sh │ │ │ └── k6.mjs │ ├── test-data │ │ └── gen-fixtures.js │ └── test │ │ ├── amp-validation.js │ │ └── build-check.js ├── src │ ├── AMPAttributes.amp.ts │ ├── client │ │ ├── adaptiveSite.ts │ │ ├── atomIframe.ts │ │ ├── bootCmp.ts │ │ ├── debug │ │ │ ├── README.md │ │ │ ├── debug.css │ │ │ └── debug.ts │ │ ├── decidePublicPath.test.ts │ │ ├── decidePublicPath.ts │ │ ├── discussion.ts │ │ ├── dynamicImport.ts │ │ ├── embedIframe.ts │ │ ├── islands │ │ │ ├── doHydration.tsx │ │ │ ├── emotion.ts │ │ │ ├── getConfig.ts │ │ │ ├── getName.ts │ │ │ ├── getPriority.ts │ │ │ ├── getProps.ts │ │ │ ├── initHydration.ts │ │ │ ├── islands.ts │ │ │ ├── onInteraction.ts │ │ │ ├── onNavigation.ts │ │ │ ├── whenIdle.ts │ │ │ └── whenVisible.ts │ │ ├── main.apps.ts │ │ ├── main.editionsCrossword.tsx │ │ ├── main.web.ts │ │ ├── newsletterEmbedIframe.ts │ │ ├── ophan │ │ │ ├── ophan.ts │ │ │ └── recordInitialPageEvents.ts │ │ ├── poorPerformanceMonitoring.ts │ │ ├── sIndicator.ts │ │ ├── sentryLoader │ │ │ ├── loadSentry.ts │ │ │ ├── sentry.ts │ │ │ ├── sentryLoader.test.ts │ │ │ └── sentryLoader.ts │ │ ├── startup.ts │ │ ├── updateIframeHeight.tsx │ │ ├── userFeatures │ │ │ ├── cookies │ │ │ │ ├── adFree.ts │ │ │ │ ├── allowRejectAll.ts │ │ │ │ ├── cookieHelpers.ts │ │ │ │ ├── hideSupportMessaging.ts │ │ │ │ ├── sIndicatorCapiKey.ts │ │ │ │ └── userBenefitsExpiry.ts │ │ │ ├── fetchJson.ts │ │ │ ├── user-features.test.ts │ │ │ ├── user-features.ts │ │ │ └── userBenefitsApi.ts │ │ └── webpackPublicPath.ts │ ├── components │ │ ├── Accessibility.importable.tsx │ │ ├── Accordion.stories.tsx │ │ ├── Accordion.tsx │ │ ├── Ad.amp.tsx │ │ ├── AdBlockAsk.importable.tsx │ │ ├── AdBlockAskLeaderboard.stories.tsx │ │ ├── AdBlockAskMPU.stories.tsx │ │ ├── AdConsent.amp.tsx │ │ ├── AdPlaceholder.apps.tsx │ │ ├── AdPortals.importable.tsx │ │ ├── AdSlot.apps.stories.tsx │ │ ├── AdSlot.apps.tsx │ │ ├── AdSlot.web.stories.tsx │ │ ├── AdSlot.web.tsx │ │ ├── AffiliateDisclaimer.tsx │ │ ├── AgeWarning.stories.tsx │ │ ├── AgeWarning.tsx │ │ ├── AllEditorialNewslettersPage.tsx │ │ ├── AlreadyVisited.importable.tsx │ │ ├── AmpExperiment.amp.tsx │ │ ├── Analytics.amp.tsx │ │ ├── AnalyticsIframe.amp.tsx │ │ ├── Answers.stories.tsx │ │ ├── Answers.tsx │ │ ├── AppsEpic.importable.stories.tsx │ │ ├── AppsEpic.importable.tsx │ │ ├── AppsFooter.importable.stories.tsx │ │ ├── AppsFooter.importable.tsx │ │ ├── AppsLightboxImage.importable.tsx │ │ ├── AppsLightboxImageStore.importable.tsx │ │ ├── ArticleBody.tsx │ │ ├── ArticleContainer.tsx │ │ ├── ArticleHeadline.mocks.ts │ │ ├── ArticleHeadline.stories.tsx │ │ ├── ArticleHeadline.tsx │ │ ├── ArticleLastUpdated.stories.tsx │ │ ├── ArticleLastUpdated.tsx │ │ ├── ArticleMeta.apps.stories.tsx │ │ ├── ArticleMeta.apps.tsx │ │ ├── ArticleMeta.web.stories.tsx │ │ ├── ArticleMeta.web.test.tsx │ │ ├── ArticleMeta.web.tsx │ │ ├── ArticlePage.amp.tsx │ │ ├── ArticlePage.tsx │ │ ├── ArticleTitle.stories.tsx │ │ ├── ArticleTitle.tsx │ │ ├── AudioAtom │ │ │ ├── AudioAtom.stories.tsx │ │ │ ├── AudioAtom.test.tsx │ │ │ └── AudioAtom.tsx │ │ ├── AudioAtomBlockComponent.amp.tsx │ │ ├── AudioAtomWrapper.importable.tsx │ │ ├── AudioPlayer │ │ │ ├── AudioPlayer.stories.tsx │ │ │ ├── AudioPlayer.tsx │ │ │ ├── components │ │ │ │ ├── Playback.tsx │ │ │ │ ├── ProgressBar.tsx │ │ │ │ ├── Wrapper.tsx │ │ │ │ └── time.tsx │ │ │ ├── stories │ │ │ │ ├── default_audio_test.mp3 │ │ │ │ └── default_audio_test.mp3.d.ts │ │ │ └── styles.ts │ │ ├── AudioPlayerWrapper.importable.tsx │ │ ├── AustralianTerritorySwitcher.importable.stories.tsx │ │ ├── AustralianTerritorySwitcher.importable.tsx │ │ ├── Avatar.stories.tsx │ │ ├── Avatar.tsx │ │ ├── BackToTop.tsx │ │ ├── Badge.tsx │ │ ├── BigNumber.stories.tsx │ │ ├── BigNumber.tsx │ │ ├── Bio.tsx │ │ ├── BlockquoteBlockComponent.stories.tsx │ │ ├── BlockquoteBlockComponent.tsx │ │ ├── Blocks.amp.tsx │ │ ├── BodyArticle.amp.tsx │ │ ├── BodyLiveblog.amp.tsx │ │ ├── Border.tsx │ │ ├── Branding.amp.tsx │ │ ├── Branding.importable.tsx │ │ ├── BrazeMessaging.importable.tsx │ │ ├── Byline.amp.stories.tsx │ │ ├── Byline.amp.test.tsx │ │ ├── Byline.amp.tsx │ │ ├── Byline.tsx │ │ ├── BylineLink.test.tsx │ │ ├── BylineLink.tsx │ │ ├── CPScottHeader.tsx │ │ ├── Callout │ │ │ ├── Callout.tsx │ │ │ ├── CalloutComponents.tsx │ │ │ ├── Deadline.tsx │ │ │ ├── Form.tsx │ │ │ ├── FormField.tsx │ │ │ ├── MessageUs.tsx │ │ │ └── callout.test.ts │ │ ├── CalloutBlockComponent.importable.tsx │ │ ├── CalloutBlockComponent.stories.tsx │ │ ├── CalloutEmbed │ │ │ ├── Form.stories.tsx │ │ │ ├── Form.test.tsx │ │ │ ├── Form.tsx │ │ │ └── FormFields │ │ │ │ ├── CheckboxSelect.tsx │ │ │ │ ├── FieldLabel.tsx │ │ │ │ ├── FileUpload.tsx │ │ │ │ ├── MultiSelect.tsx │ │ │ │ ├── RadioSelect.tsx │ │ │ │ ├── Select.tsx │ │ │ │ ├── TextArea.tsx │ │ │ │ └── TextInput.tsx │ │ ├── CalloutEmbedBlockComponent.importable.tsx │ │ ├── CalloutEmbedBlockComponent.stories.tsx │ │ ├── Caption.amp.tsx │ │ ├── Caption.stories.tsx │ │ ├── Caption.tsx │ │ ├── CaptionBlockComponent.stories.tsx │ │ ├── CaptionBlockComponent.tsx │ │ ├── Card │ │ │ ├── Card.stories.tsx │ │ │ ├── Card.tsx │ │ │ └── components │ │ │ │ ├── AvatarContainer.tsx │ │ │ │ ├── CardAge.tsx │ │ │ │ ├── CardBranding.tsx │ │ │ │ ├── CardFooter.stories.tsx │ │ │ │ ├── CardFooter.tsx │ │ │ │ ├── CardLayout.tsx │ │ │ │ ├── CardLink.tsx │ │ │ │ ├── CardWrapper.tsx │ │ │ │ ├── ContentWrapper.tsx │ │ │ │ ├── HeadlineWrapper.tsx │ │ │ │ ├── ImageWrapper.tsx │ │ │ │ ├── LI.tsx │ │ │ │ ├── PlayIcon.tsx │ │ │ │ ├── SvgWaveform.tsx │ │ │ │ ├── TrailText.tsx │ │ │ │ └── UL.tsx │ │ ├── CardCommentCount.importable.stories.tsx │ │ ├── CardCommentCount.importable.tsx │ │ ├── CardHeadline.stories.tsx │ │ ├── CardHeadline.tsx │ │ ├── CardPicture.tsx │ │ ├── Carousel.importable.tsx │ │ ├── Carousel.stories.tsx │ │ ├── CarouselForNewsletters.importable.tsx │ │ ├── CarouselNavigationButtons.tsx │ │ ├── CartoonComponent.mocks.ts │ │ ├── CartoonComponent.stories.tsx │ │ ├── CartoonComponent.tsx │ │ ├── ChartAtom.importable.tsx │ │ ├── ChartAtom.stories.tsx │ │ ├── ChartAtom.test.tsx │ │ ├── ClickToView.stories.tsx │ │ ├── ClickToView.test.tsx │ │ ├── ClickToView.tsx │ │ ├── CodeBlockComponent.stories.tsx │ │ ├── CodeBlockComponent.tsx │ │ ├── CommentBlockComponent.amp.tsx │ │ ├── CommentBlockComponent.stories.tsx │ │ ├── CommentBlockComponent.tsx │ │ ├── CommentCount.importable.tsx │ │ ├── ConfigContext.test.tsx │ │ ├── ConfigContext.tsx │ │ ├── ContainerOverrides.tsx │ │ ├── ContainerTitle.stories.tsx │ │ ├── ContainerTitle.tsx │ │ ├── ContentABTest.amp.test.tsx │ │ ├── ContentABTest.amp.tsx │ │ ├── ContentAtomBlockComponent.amp.tsx │ │ ├── Contributor.test.tsx │ │ ├── Contributor.tsx │ │ ├── ContributorAvatar.tsx │ │ ├── CricketScoreboard.stories.tsx │ │ ├── CricketScoreboard.test.tsx │ │ ├── CricketScoreboard.tsx │ │ ├── CricketScorecard.stories.tsx │ │ ├── CricketScorecard.tsx │ │ ├── CricketScorecardPage.tsx │ │ ├── CrosswordComponent.importable.tsx │ │ ├── CrosswordInstructions.tsx │ │ ├── CrosswordLinks.tsx │ │ ├── CrosswordSelect.editions.stories.tsx │ │ ├── CrosswordSelect.editions.tsx │ │ ├── CrosswordSetter.tsx │ │ ├── Crosswords.editions.stories.tsx │ │ ├── Crosswords.editions.tsx │ │ ├── DarkModeMessage.tsx │ │ ├── DateTime.stories.tsx │ │ ├── DateTime.tsx │ │ ├── Dateline.tsx │ │ ├── DecideContainer.tsx │ │ ├── DecideContainerByTrails.stories.tsx │ │ ├── DecideContainerByTrails.tsx │ │ ├── DecideLines.tsx │ │ ├── DesignTag.stories.tsx │ │ ├── DesignTag.tsx │ │ ├── Details.tsx │ │ ├── Discussion.stories.tsx │ │ ├── Discussion.test.tsx │ │ ├── Discussion.tsx │ │ ├── Discussion │ │ │ ├── AbuseReportForm.stories.tsx │ │ │ ├── AbuseReportForm.test.tsx │ │ │ ├── AbuseReportForm.tsx │ │ │ ├── Avatar.stories.tsx │ │ │ ├── Avatar.tsx │ │ │ ├── Badges.stories.tsx │ │ │ ├── Badges.tsx │ │ │ ├── Column.tsx │ │ │ ├── Comment.stories.tsx │ │ │ ├── Comment.tsx │ │ │ ├── CommentContainer.stories.tsx │ │ │ ├── CommentContainer.test.tsx │ │ │ ├── CommentContainer.tsx │ │ │ ├── CommentForm.stories.tsx │ │ │ ├── CommentForm.tsx │ │ │ ├── CommentReplyPreview.stories.tsx │ │ │ ├── CommentReplyPreview.tsx │ │ │ ├── Comments.stories.tsx │ │ │ ├── Comments.tsx │ │ │ ├── Discussion.test.tsx │ │ │ ├── Dropdown.stories.tsx │ │ │ ├── Dropdown.test.tsx │ │ │ ├── Dropdown.tsx │ │ │ ├── Filters.stories.tsx │ │ │ ├── Filters.tsx │ │ │ ├── FirstCommentWelcome.stories.tsx │ │ │ ├── FirstCommentWelcome.tsx │ │ │ ├── LoadingComments.stories.tsx │ │ │ ├── LoadingComments.tsx │ │ │ ├── LoadingPicks.stories.tsx │ │ │ ├── LoadingPicks.tsx │ │ │ ├── Pagination.stories.tsx │ │ │ ├── Pagination.test.tsx │ │ │ ├── Pagination.tsx │ │ │ ├── PillarButton.stories.tsx │ │ │ ├── PillarButton.tsx │ │ │ ├── Preview.stories.tsx │ │ │ ├── Preview.tsx │ │ │ ├── RecommendationCount.stories.tsx │ │ │ ├── RecommendationCount.tsx │ │ │ ├── Row.tsx │ │ │ ├── Timestamp.stories.tsx │ │ │ ├── Timestamp.tsx │ │ │ ├── TopPick.stories.tsx │ │ │ ├── TopPick.tsx │ │ │ ├── TopPicks.stories.tsx │ │ │ └── TopPicks.tsx │ │ ├── DiscussionApps.importable.tsx │ │ ├── DiscussionLayout.tsx │ │ ├── DiscussionMeta.importable.tsx │ │ ├── DiscussionWeb.importable.tsx │ │ ├── DispatchContext.tsx │ │ ├── Distribution.stories.tsx │ │ ├── Distribution.tsx │ │ ├── DividerBlockComponent.stories.tsx │ │ ├── DividerBlockComponent.tsx │ │ ├── DocumentBlockComponent.importable.tsx │ │ ├── DocumentBlockComponent.stories.tsx │ │ ├── DocumentBlockComponent.test.tsx │ │ ├── Doughnut.stories.tsx │ │ ├── Doughnut.test.tsx │ │ ├── Doughnut.tsx │ │ ├── DropCap.tsx │ │ ├── Dropcap.stories.tsx │ │ ├── Dropdown.importable.tsx │ │ ├── Dropdown.stories.tsx │ │ ├── Dropdown.test.tsx │ │ ├── DynamicFast.stories.tsx │ │ ├── DynamicFast.tsx │ │ ├── DynamicPackage.stories.tsx │ │ ├── DynamicPackage.tsx │ │ ├── DynamicSlow.stories.tsx │ │ ├── DynamicSlow.tsx │ │ ├── DynamicSlowMPU.stories.tsx │ │ ├── DynamicSlowMPU.tsx │ │ ├── EditionSwitcherBanner.importable.tsx │ │ ├── EditionSwitcherBanner.stories.tsx │ │ ├── EditionSwitcherBanner.test.tsx │ │ ├── EditionsCrosswordPage.tsx │ │ ├── EditorialButton │ │ │ ├── EditorialButton.stories.tsx │ │ │ ├── EditorialButton.tsx │ │ │ ├── EditorialLinkButton.stories.tsx │ │ │ ├── EditorialLinkButton.tsx │ │ │ └── styles.ts │ │ ├── ElectionTrackers │ │ │ ├── ChangeBars.stories.tsx │ │ │ ├── ChangeBars.tsx │ │ │ ├── StackedProgress.stories.tsx │ │ │ ├── StackedProgress.tsx │ │ │ ├── ValuesWithChange.stories.tsx │ │ │ ├── ValuesWithChange.tsx │ │ │ ├── Versus.stories.tsx │ │ │ └── Versus.tsx │ │ ├── ElementContainer.tsx │ │ ├── Elements.amp.tsx │ │ ├── EmailSignUpWrapper.stories.tsx │ │ ├── EmailSignUpWrapper.tsx │ │ ├── EmailSignup.stories.tsx │ │ ├── EmailSignup.tsx │ │ ├── EmbedBlockComponent.amp.tsx │ │ ├── EmbedBlockComponent.importable.tsx │ │ ├── EndNote.tsx │ │ ├── EnhancePinnedPost.importable.tsx │ │ ├── Epic.amp.tsx │ │ ├── EpicContent.apps.tsx │ │ ├── Expandable.amp.tsx │ │ ├── ExpandableAtom │ │ │ ├── Body.tsx │ │ │ ├── Container.tsx │ │ │ ├── Footer.tsx │ │ │ └── Summary.tsx │ │ ├── ExplainerAtom.stories.tsx │ │ ├── ExplainerAtom.test.tsx │ │ ├── ExplainerAtom.tsx │ │ ├── FeatureCard.stories.tsx │ │ ├── FeatureCard.tsx │ │ ├── FeatureCardCardAge.tsx │ │ ├── FeatureCardCommentCount.tsx │ │ ├── FetchOnwardsData.importable.tsx │ │ ├── Figure.stories.tsx │ │ ├── Figure.tsx │ │ ├── FilterKeyEventsToggle.importable.tsx │ │ ├── FirstPublished.stories.tsx │ │ ├── FirstPublished.tsx │ │ ├── FixedLargeSlowXIV.stories.tsx │ │ ├── FixedLargeSlowXIV.tsx │ │ ├── FixedMediumFastXI.stories.tsx │ │ ├── FixedMediumFastXI.tsx │ │ ├── FixedMediumFastXII.stories.tsx │ │ ├── FixedMediumFastXII.tsx │ │ ├── FixedMediumSlowVI.stories.tsx │ │ ├── FixedMediumSlowVI.tsx │ │ ├── FixedMediumSlowVII.stories.tsx │ │ ├── FixedMediumSlowVII.tsx │ │ ├── FixedMediumSlowXIIMPU.stories.tsx │ │ ├── FixedMediumSlowXIIMPU.tsx │ │ ├── FixedSmallFastVIII.stories.tsx │ │ ├── FixedSmallFastVIII.tsx │ │ ├── FixedSmallSlowI.stories.tsx │ │ ├── FixedSmallSlowI.tsx │ │ ├── FixedSmallSlowIII.stories.tsx │ │ ├── FixedSmallSlowIII.tsx │ │ ├── FixedSmallSlowIV.stories.tsx │ │ ├── FixedSmallSlowIV.tsx │ │ ├── FixedSmallSlowVHalf.stories.tsx │ │ ├── FixedSmallSlowVHalf.tsx │ │ ├── FixedSmallSlowVMPU.stories.tsx │ │ ├── FixedSmallSlowVMPU.tsx │ │ ├── FixedSmallSlowVThird.stories.tsx │ │ ├── FixedSmallSlowVThird.tsx │ │ ├── Flex.tsx │ │ ├── FlexibleGeneral.stories.tsx │ │ ├── FlexibleGeneral.test.tsx │ │ ├── FlexibleGeneral.tsx │ │ ├── FlexibleSpecial.stories.tsx │ │ ├── FlexibleSpecial.tsx │ │ ├── FocusStyles.importable.tsx │ │ ├── FollowButtons.stories.tsx │ │ ├── FollowButtons.test.tsx │ │ ├── FollowButtons.tsx │ │ ├── FollowWrapper.importable.tsx │ │ ├── FootballCompetitionSelect.stories.tsx │ │ ├── FootballCompetitionSelect.tsx │ │ ├── FootballMatchList.stories.tsx │ │ ├── FootballMatchList.test.tsx │ │ ├── FootballMatchList.tsx │ │ ├── FootballMatchSummary.stories.tsx │ │ ├── FootballMatchSummary.tsx │ │ ├── FootballMatchesPage.stories.tsx │ │ ├── FootballMatchesPage.tsx │ │ ├── FootballMatchesPageWrapper.importable.tsx │ │ ├── FootballTable.stories.tsx │ │ ├── FootballTable.tsx │ │ ├── FootballTableForm.stories.tsx │ │ ├── FootballTableForm.tsx │ │ ├── FootballTableList.stories.tsx │ │ ├── FootballTableList.tsx │ │ ├── FootballTablesCompetitionSelect.importable.tsx │ │ ├── FootballTablesPage.stories.tsx │ │ ├── FootballTablesPage.tsx │ │ ├── Footer.amp.tsx │ │ ├── Footer.stories.tsx │ │ ├── Footer.tsx │ │ ├── FooterLabel.importable.tsx │ │ ├── FooterReaderRevenueLinks.importable.tsx │ │ ├── FooterReaderRevenueLinks.stories.tsx │ │ ├── FooterReaderRevenueLinks.test.tsx │ │ ├── FormatBoundary.tsx │ │ ├── FrontCard.tsx │ │ ├── FrontMostViewed.tsx │ │ ├── FrontPage.tsx │ │ ├── FrontPagination.stories.tsx │ │ ├── FrontPagination.tsx │ │ ├── FrontSection.stories.tsx │ │ ├── FrontSection.tsx │ │ ├── FrontSectionTitle.tsx │ │ ├── FrontSubNav.importable.tsx │ │ ├── FrontsAdSlots.test.tsx │ │ ├── FrontsAdSlots.tsx │ │ ├── GetCricketScoreboard.importable.tsx │ │ ├── GetMatchNav.importable.tsx │ │ ├── GetMatchStats.importable.tsx │ │ ├── GetMatchTabs.importable.tsx │ │ ├── GoalAttempts.stories.tsx │ │ ├── GoalAttempts.tsx │ │ ├── GridItem.tsx │ │ ├── GroupedNewsletterList.tsx │ │ ├── GuVideoBlockComponent.amp.tsx │ │ ├── GuVideoBlockComponent.tsx │ │ ├── GuardianLabsLines.tsx │ │ ├── GuideAtom │ │ │ ├── GuideAtom.stories.tsx │ │ │ ├── GuideAtom.test.tsx │ │ │ └── GuideAtom.tsx │ │ ├── GuideAtomWrapper.importable.tsx │ │ ├── Header.amp.tsx │ │ ├── HeaderAdSlot.tsx │ │ ├── Heading.tsx │ │ ├── HeadlineByline.stories.tsx │ │ ├── HeadlineByline.tsx │ │ ├── Hide.tsx │ │ ├── HighlightBlockComponent.stories.tsx │ │ ├── HighlightBlockComponent.tsx │ │ ├── ImageBlockComponent.amp.tsx │ │ ├── ImageBlockComponent.mocks.ts │ │ ├── ImageBlockComponent.stories.tsx │ │ ├── ImageBlockComponent.tsx │ │ ├── ImageComponent.tsx │ │ ├── InlineAd.amp.test.tsx │ │ ├── InlineAd.amp.tsx │ │ ├── InlineSkipToWrapper.tsx │ │ ├── InstagramBlockComponent.importable.tsx │ │ ├── InteractiveAtom.stories.tsx │ │ ├── InteractiveAtom.tsx │ │ ├── InteractiveAtomBlockComponent.amp.tsx │ │ ├── InteractiveAtomMessenger.importable.tsx │ │ ├── InteractiveBlockComponent.amp.tsx │ │ ├── InteractiveBlockComponent.importable.tsx │ │ ├── InteractiveBlockComponent.stories.tsx │ │ ├── InteractiveContentsBlockComponent.importable.tsx │ │ ├── InteractiveContentsBlockComponent.stories.tsx │ │ ├── InteractiveLayoutAtom.stories.tsx │ │ ├── InteractiveLayoutAtom.test.tsx │ │ ├── InteractiveLayoutAtom.tsx │ │ ├── InteractivesNativePlatformWrapper.importable.tsx │ │ ├── Island.test.tsx │ │ ├── Island.tsx │ │ ├── ItemLinkBlockElement.stories.tsx │ │ ├── ItemLinkBlockElement.tsx │ │ ├── JsonScript.amp.tsx │ │ ├── KeyEventCard.stories.tsx │ │ ├── KeyEventCard.tsx │ │ ├── KeyEvents.amp.tsx │ │ ├── KeyEventsCarousel.importable.tsx │ │ ├── KeyEventsCarousel.stories.tsx │ │ ├── KeyTakeaway.tsx │ │ ├── KeyTakeaways.stories.tsx │ │ ├── KeyTakeaways.tsx │ │ ├── Kicker.stories.tsx │ │ ├── Kicker.tsx │ │ ├── KnowledgeQuizAtom.importable.tsx │ │ ├── KnowledgeQuizAtom.stories.tsx │ │ ├── KnowledgeQuizAtom.test.tsx │ │ ├── LabsHeader.stories.tsx │ │ ├── LabsHeader.tsx │ │ ├── LabsSection.stories.tsx │ │ ├── LabsSection.tsx │ │ ├── LastUpdated.stories.tsx │ │ ├── LastUpdated.tsx │ │ ├── LatestLinks.importable.stories.tsx │ │ ├── LatestLinks.importable.tsx │ │ ├── Lazy.tsx │ │ ├── LeftColumn.stories.tsx │ │ ├── LeftColumn.tsx │ │ ├── Lightbox.stories.tsx │ │ ├── Lightbox.tsx │ │ ├── LightboxCaption.tsx │ │ ├── LightboxHash.importable.tsx │ │ ├── LightboxImages.tsx │ │ ├── LightboxJavascript.tsx │ │ ├── LightboxLayout.importable.tsx │ │ ├── LightboxLink.tsx │ │ ├── LightboxLoader.tsx │ │ ├── Lineup.stories.tsx │ │ ├── Lineup.tsx │ │ ├── LinkHeadline.stories.tsx │ │ ├── LinkHeadline.tsx │ │ ├── LiveBlock.stories.tsx │ │ ├── LiveBlock.tsx │ │ ├── LiveBlockContainer.tsx │ │ ├── LiveBlogBlocksAndAdverts.tsx │ │ ├── LiveBlogEpic.importable.tsx │ │ ├── LiveBlogRenderer.tsx │ │ ├── LiveblogGutterAskWrapper.importable.tsx │ │ ├── LiveblogNotifications.importable.tsx │ │ ├── Liveness.importable.tsx │ │ ├── Localisation.ts │ │ ├── LoopVideo.importable.tsx │ │ ├── LoopVideo.stories.tsx │ │ ├── LoopVideoPlayer.tsx │ │ ├── LoopVideoProgressBar.tsx │ │ ├── MainMedia.amp.tsx │ │ ├── MainMedia.tsx │ │ ├── MainMediaEmbedBlockComponent.tsx │ │ ├── MainMediaGallery.stories.tsx │ │ ├── MainMediaGallery.tsx │ │ ├── MaintainAspectRatio.tsx │ │ ├── ManyNewsletterSignUp.importable.tsx │ │ ├── ManyNewsletterSignUp.stories.tsx │ │ ├── ManyNewslettersForm.tsx │ │ ├── MapEmbedBlockComponent.importable.tsx │ │ ├── Masthead │ │ │ ├── HighlightsCard.stories.tsx │ │ │ ├── HighlightsCard.tsx │ │ │ ├── Masthead.stories.tsx │ │ │ ├── Masthead.tsx │ │ │ └── Titlepiece │ │ │ │ ├── EditionDropdown.stories.tsx │ │ │ │ ├── EditionDropdown.tsx │ │ │ │ ├── ExpandedNav │ │ │ │ ├── CollapseSectionButton.tsx │ │ │ │ ├── ExpandedNav.stories.tsx │ │ │ │ ├── ExpandedNav.tsx │ │ │ │ ├── MoreSection.tsx │ │ │ │ ├── Pillar.tsx │ │ │ │ ├── ReaderRevenueLinks.tsx │ │ │ │ ├── SearchBar.tsx │ │ │ │ └── Sections.tsx │ │ │ │ ├── Grid.tsx │ │ │ │ ├── Logo.tsx │ │ │ │ ├── Nav.mock.tsx │ │ │ │ ├── Pillars.stories.tsx │ │ │ │ ├── Pillars.tsx │ │ │ │ ├── SubNav.tsx │ │ │ │ ├── VeggieBurger.tsx │ │ │ │ ├── commonStyles.ts │ │ │ │ └── constants.ts │ │ ├── MatchNav.stories.tsx │ │ ├── MatchNav.tsx │ │ ├── MatchStats.stories.tsx │ │ ├── MatchStats.tsx │ │ ├── MatchTabs.stories.tsx │ │ ├── MatchTabs.tsx │ │ ├── MediaDuration.tsx │ │ ├── MediaMeta.tsx │ │ ├── Metrics.importable.tsx │ │ ├── MiniCard.tsx │ │ ├── MiniProfile.tsx │ │ ├── MiniProfiles.stories.tsx │ │ ├── MiniProfiles.tsx │ │ ├── MostPopularFooterGrid.stories.tsx │ │ ├── MostPopularFooterGrid.tsx │ │ ├── MostViewed.mocks.ts │ │ ├── MostViewedFooter.importable.tsx │ │ ├── MostViewedFooter.test.tsx │ │ ├── MostViewedFooterData.importable.tsx │ │ ├── MostViewedFooterGrid.tsx │ │ ├── MostViewedFooterItem.tsx │ │ ├── MostViewedFooterLayout.stories.tsx │ │ ├── MostViewedFooterLayout.tsx │ │ ├── MostViewedFooterPlaceholder.stories.tsx │ │ ├── MostViewedFooterPlaceholder.tsx │ │ ├── MostViewedRight.stories.tsx │ │ ├── MostViewedRight.test.tsx │ │ ├── MostViewedRight.tsx │ │ ├── MostViewedRightItem.tsx │ │ ├── MostViewedRightWithAd.importable.tsx │ │ ├── MostViewedRightWrapper.tsx │ │ ├── Moustache.amp.tsx │ │ ├── MultiByline.tsx │ │ ├── MultiBylines.stories.tsx │ │ ├── MultiBylines.tsx │ │ ├── MultiImageBlockComponent.mocks.tsx │ │ ├── MultiImageBlockComponent.stories.tsx │ │ ├── MultiImageBlockComponent.tsx │ │ ├── NavList.stories.tsx │ │ ├── NavList.tsx │ │ ├── NewsletterBadge.stories.tsx │ │ ├── NewsletterBadge.tsx │ │ ├── NewsletterCard.tsx │ │ ├── NewsletterDetail.stories.tsx │ │ ├── NewsletterDetail.tsx │ │ ├── NewsletterFrequency.stories.tsx │ │ ├── NewsletterFrequency.tsx │ │ ├── NewsletterPageHeading.tsx │ │ ├── NewsletterPrivacyMessage.stories.tsx │ │ ├── NewsletterPrivacyMessage.tsx │ │ ├── NumberedTitleBlockComponent.stories.tsx │ │ ├── NumberedTitleBlockComponent.tsx │ │ ├── Onward.amp.tsx │ │ ├── OnwardContainer.amp.tsx │ │ ├── OnwardsUpper.importable.test.tsx │ │ ├── OnwardsUpper.importable.tsx │ │ ├── Pagination.amp.stories.tsx │ │ ├── Pagination.amp.tsx │ │ ├── Pagination.stories.tsx │ │ ├── Pagination.tsx │ │ ├── PaidForBand.amp.tsx │ │ ├── Palettes.stories.tsx │ │ ├── Permutive.amp.tsx │ │ ├── PersonalityQuizAtom.importable.tsx │ │ ├── PersonalityQuizAtom.stories.tsx │ │ ├── PersonalityQuizAtom.test.tsx │ │ ├── Picture.tsx │ │ ├── Pill.stories.tsx │ │ ├── Pill.tsx │ │ ├── PinnedPost.stories.tsx │ │ ├── PinnedPost.tsx │ │ ├── Placeholder.stories.tsx │ │ ├── Placeholder.tsx │ │ ├── PodcastCoverImage.tsx │ │ ├── PodcastMeta.stories.tsx │ │ ├── PodcastMeta.tsx │ │ ├── PrivacySettingsLink.importable.tsx │ │ ├── ProfileAtom.importable.tsx │ │ ├── ProfileAtom.stories.tsx │ │ ├── ProfileAtom.test.tsx │ │ ├── ProfileAtomWrapper.importable.tsx │ │ ├── PullQuoteBlockComponent.stories.tsx │ │ ├── PullQuoteBlockComponent.tsx │ │ ├── PullquoteBlockComponent.amp.tsx │ │ ├── PulsingDot.importable.tsx │ │ ├── PulsingDot.test.tsx │ │ ├── QAndAExplainer.tsx │ │ ├── QAndAExplainers.stories.tsx │ │ ├── QAndAExplainers.tsx │ │ ├── QandaAtom.importable.tsx │ │ ├── QandaAtom.stories.tsx │ │ ├── QandaAtom.test.tsx │ │ ├── QuoteIcon.tsx │ │ ├── ReaderRevenueButton.amp.tsx │ │ ├── ReaderRevenueDev.importable.tsx │ │ ├── RelativeTime.importable.test.tsx │ │ ├── RelativeTime.importable.tsx │ │ ├── RewrappedComponent.tsx │ │ ├── RichLink.stories.tsx │ │ ├── RichLink.tsx │ │ ├── RichLinkBlockComponent.amp.tsx │ │ ├── RichLinkComponent.importable.test.tsx │ │ ├── RichLinkComponent.importable.tsx │ │ ├── RightColumn.tsx │ │ ├── Score.stories.tsx │ │ ├── Score.tsx │ │ ├── ScrollableCarousel.tsx │ │ ├── ScrollableFeature.importable.tsx │ │ ├── ScrollableFeature.stories.tsx │ │ ├── ScrollableHighlights.importable.tsx │ │ ├── ScrollableHighlights.stories.tsx │ │ ├── ScrollableMedium.importable.tsx │ │ ├── ScrollableMedium.stories.tsx │ │ ├── ScrollableSmall.importable.tsx │ │ ├── ScrollableSmall.stories.tsx │ │ ├── Section.stories.tsx │ │ ├── Section.tsx │ │ ├── SecureSignup.importable.tsx │ │ ├── SendTargetingParams.importable.tsx │ │ ├── SeriesLink.amp.tsx │ │ ├── SeriesSectionLink.tsx │ │ ├── SetABTests.importable.tsx │ │ ├── SetAdTargeting.importable.tsx │ │ ├── ShadyPie.stories.tsx │ │ ├── ShadyPie.tsx │ │ ├── ShareButton.importable.tsx │ │ ├── ShareButton.stories.tsx │ │ ├── ShareIcons.amp.tsx │ │ ├── ShowHideButton.tsx │ │ ├── ShowHideContainers.importable.tsx │ │ ├── ShowMore.importable.tsx │ │ ├── ShowMore.stories.tsx │ │ ├── ShowMoreButton.amp.tsx │ │ ├── Sidebar.amp.tsx │ │ ├── SignInGate │ │ │ ├── README.md │ │ │ ├── SignInGate.stories.tsx │ │ │ ├── componentEventTracking.tsx │ │ │ ├── dismissGate.test.ts │ │ │ ├── dismissGate.ts │ │ │ ├── displayRules.test.ts │ │ │ ├── displayRules.ts │ │ │ ├── gateDesigns │ │ │ │ ├── SignInGateAuxia.tsx │ │ │ │ ├── SignInGateCustomizableText.tsx │ │ │ │ ├── SignInGateFakeSocial.tsx │ │ │ │ ├── SignInGateMain.tsx │ │ │ │ ├── SignInGateMainCheckoutComplete.test.tsx │ │ │ │ ├── SignInGateMainCheckoutComplete.tsx │ │ │ │ └── shared.tsx │ │ │ ├── gates │ │ │ │ ├── alternative-wording-control.tsx │ │ │ │ ├── alternative-wording-guardian-live.tsx │ │ │ │ ├── alternative-wording-saturday-edition.tsx │ │ │ │ ├── fake-social-variant.tsx │ │ │ │ ├── main-control.ts │ │ │ │ ├── main-mandatory-variant.tsx │ │ │ │ └── main-variant.tsx │ │ │ ├── signInGateMappings.ts │ │ │ └── types.ts │ │ ├── SignInGateSelector.importable.tsx │ │ ├── SignedInAs.stories.tsx │ │ ├── SignedInAs.tsx │ │ ├── SkipTo.tsx │ │ ├── Slideshow.stories.tsx │ │ ├── Slideshow.tsx │ │ ├── SlideshowCarousel.importable.tsx │ │ ├── SlideshowCarousel.stories.tsx │ │ ├── SlideshowCarouselScrollingDots.tsx │ │ ├── SlotBodyEnd.importable.tsx │ │ ├── SlotBodyEnd │ │ │ ├── BrazeEpic.stories.tsx │ │ │ ├── BrazeEpic.tsx │ │ │ └── ReaderRevenueEpic.tsx │ │ ├── Snap.stories.tsx │ │ ├── Snap.tsx │ │ ├── SnapCssSandbox.tsx │ │ ├── SoundcloudBlockComponent.amp.tsx │ │ ├── SoundcloudBlockComponent.tsx │ │ ├── SportDataPageComponent.tsx │ │ ├── SpotifyBlockComponent.importable.tsx │ │ ├── Standfirst.amp.tsx │ │ ├── Standfirst.stories.tsx │ │ ├── Standfirst.test.tsx │ │ ├── Standfirst.tsx │ │ ├── StarRating.amp.tsx │ │ ├── StarRating │ │ │ ├── StarRating.stories.tsx │ │ │ └── StarRating.tsx │ │ ├── StarRatingBlockComponent.stories.tsx │ │ ├── StarRatingBlockComponent.tsx │ │ ├── StaticFeatureTwo.stories.tsx │ │ ├── StaticFeatureTwo.tsx │ │ ├── StaticMediumFour.stories.tsx │ │ ├── StaticMediumFour.tsx │ │ ├── StickyAd.amp.tsx │ │ ├── StickyBottomBanner.importable.tsx │ │ ├── StickyBottomBanner │ │ │ ├── BrazeBanner.stories.tsx │ │ │ ├── BrazeBanner.tsx │ │ │ └── ReaderRevenueBanner.tsx │ │ ├── SubMeta.amp.tsx │ │ ├── SubMeta.stories.tsx │ │ ├── SubMeta.tsx │ │ ├── SubNav.importable.tsx │ │ ├── SubNav.stories.tsx │ │ ├── Subheading.tsx │ │ ├── SubheadingBlockComponent.amp.tsx │ │ ├── SubheadingBlockComponent.stories.tsx │ │ ├── SubheadingBlockComponent.tsx │ │ ├── SupportingContent.stories.tsx │ │ ├── SupportingContent.tsx │ │ ├── SvgCrossword.tsx │ │ ├── SvgMediaControlsPlay.tsx │ │ ├── TableBlockComponent.stories.tsx │ │ ├── TableBlockComponent.tsx │ │ ├── TableOfContents.importable.tsx │ │ ├── TableOfContents.stories.tsx │ │ ├── TagPage.tsx │ │ ├── TagPageHeader.stories.tsx │ │ ├── TagPageHeader.tsx │ │ ├── TextBlockComponent.amp.tsx │ │ ├── TextBlockComponent.stories.tsx │ │ ├── TextBlockComponent.tsx │ │ ├── Timeline.stories.tsx │ │ ├── Timeline.tsx │ │ ├── TimelineAtom.amp.tsx │ │ ├── TimelineAtom.importable.tsx │ │ ├── TimelineAtom.stories.tsx │ │ ├── TimelineAtom.test.tsx │ │ ├── Titlepiece.importable.tsx │ │ ├── Titlepiece.stories.tsx │ │ ├── Toast.stories.tsx │ │ ├── Toast.tsx │ │ ├── TopBar.importable.tsx │ │ ├── TopBar.stories.tsx │ │ ├── TopBarLink.tsx │ │ ├── TopBarMyAccount.tsx │ │ ├── TopBarSupport.importable.tsx │ │ ├── TopMeta.amp.tsx │ │ ├── TopMetaAnalysis.amp.tsx │ │ ├── TopMetaExtras.amp.tsx │ │ ├── TopMetaLiveblog.amp.tsx │ │ ├── TopMetaNews.amp.tsx │ │ ├── TopMetaOpinion.amp.tsx │ │ ├── TopMetaPaidContent.amp.tsx │ │ ├── Treats.stories.tsx │ │ ├── Treats.tsx │ │ ├── TrendingTopics.tsx │ │ ├── TweetBlockComponent.importable.tsx │ │ ├── TwitterBlockComponent.amp.tsx │ │ ├── UnsafeEmbedBlockComponent.importable.tsx │ │ ├── UnsafeEmbedBlockComponent.stories.tsx │ │ ├── VideoAtom.stories.tsx │ │ ├── VideoAtom.tsx │ │ ├── VideoFacebookBlockComponent.importable.tsx │ │ ├── VideoFacebookBlockComponent.stories.tsx │ │ ├── VideoVimeoBlockComponent.amp.tsx │ │ ├── VideoYoutubeBlockComponent.amp.tsx │ │ ├── VimeoBlockComponent.stories.tsx │ │ ├── VimeoBlockComponent.tsx │ │ ├── VineBlockComponent.importable.tsx │ │ ├── WaveForm.stories.tsx │ │ ├── WaveForm.tsx │ │ ├── WitnessBlockComponent.stories.tsx │ │ ├── WitnessBlockComponent.tsx │ │ ├── YoutubeAtom │ │ │ ├── YoutubeAtom.stories.tsx │ │ │ ├── YoutubeAtom.test.tsx │ │ │ ├── YoutubeAtom.tsx │ │ │ ├── YoutubeAtomExpiredOverlay.tsx │ │ │ ├── YoutubeAtomFeatureCardOverlay.tsx │ │ │ ├── YoutubeAtomOverlay.tsx │ │ │ ├── YoutubeAtomPicture.tsx │ │ │ ├── YoutubeAtomPlaceholder.tsx │ │ │ ├── YoutubeAtomPlayer.tsx │ │ │ ├── YoutubeAtomSticky.tsx │ │ │ ├── YoutubePlayer.ts │ │ │ ├── eventEmitters.ts │ │ │ ├── ima.d.ts │ │ │ └── loadYouTubeApi.ts │ │ ├── YoutubeBlockComponent.amp.tsx │ │ ├── YoutubeBlockComponent.importable.tsx │ │ ├── YoutubeBlockComponent.stories.tsx │ │ ├── YoutubeEmbedBlockComponent.stories.tsx │ │ ├── YoutubeEmbedBlockComponent.tsx │ │ ├── marketing │ │ │ ├── banners │ │ │ │ ├── ThreeTierChoiceCardsV2.tsx │ │ │ │ ├── common │ │ │ │ │ ├── BannerWrapper.tsx │ │ │ │ │ ├── PaymentCards.tsx │ │ │ │ │ └── types.tsx │ │ │ │ ├── designableBanner │ │ │ │ │ ├── DesignableBanner.tsx │ │ │ │ │ ├── DesignableBannerV2.tsx │ │ │ │ │ ├── components │ │ │ │ │ │ ├── BannerText.tsx │ │ │ │ │ │ ├── CustomArticleCountCopy.tsx │ │ │ │ │ │ ├── DesignableBannerArticleCount.tsx │ │ │ │ │ │ ├── DesignableBannerArticleCountOptOut.tsx │ │ │ │ │ │ ├── DesignableBannerBody.tsx │ │ │ │ │ │ ├── DesignableBannerCloseButton.tsx │ │ │ │ │ │ ├── DesignableBannerCtas.tsx │ │ │ │ │ │ ├── DesignableBannerCtasV2.tsx │ │ │ │ │ │ ├── DesignableBannerHeader.tsx │ │ │ │ │ │ ├── DesignableBannerReminder.tsx │ │ │ │ │ │ ├── DesignableBannerReminderSignedOut.tsx │ │ │ │ │ │ ├── DesignableBannerVisual.tsx │ │ │ │ │ │ └── choiceCards │ │ │ │ │ │ │ ├── ChoiceCardInteractive.tsx │ │ │ │ │ │ │ ├── ChoiceCards.tsx │ │ │ │ │ │ │ └── ChoiceCardsSupportCta.tsx │ │ │ │ │ ├── settings.ts │ │ │ │ │ ├── stories │ │ │ │ │ │ ├── DesignableBanner.stories.tsx │ │ │ │ │ │ └── DesignableBannerV2.stories.tsx │ │ │ │ │ └── styles │ │ │ │ │ │ ├── buttonStyles.ts │ │ │ │ │ │ └── templateStyles.ts │ │ │ │ ├── signInPrompt │ │ │ │ │ ├── SignInPromptBanner.stories.tsx │ │ │ │ │ └── SignInPromptBanner.tsx │ │ │ │ └── utils │ │ │ │ │ ├── localStorage.ts │ │ │ │ │ ├── storybook.ts │ │ │ │ │ └── withCloseable.tsx │ │ │ ├── epics │ │ │ │ ├── BylineWithHeadshot.tsx │ │ │ │ ├── ContributionsEpic.stories.tsx │ │ │ │ ├── ContributionsEpic.test.tsx │ │ │ │ ├── ContributionsEpic.tsx │ │ │ │ ├── ContributionsEpicArticleCountAboveWithOptOut.tsx │ │ │ │ ├── ContributionsEpicNewsletterSignup.tsx │ │ │ │ ├── ContributionsEpicSignInCta.tsx │ │ │ │ ├── ContributionsLiveblogEpic.stories.tsx │ │ │ │ ├── ContributionsLiveblogEpic.tsx │ │ │ │ ├── ThreeTierChoiceCards.tsx │ │ │ │ ├── ctas │ │ │ │ │ ├── ContributionsEpicButtons.tsx │ │ │ │ │ ├── ContributionsEpicChoiceCards.tsx │ │ │ │ │ ├── ContributionsEpicCtasContainer.tsx │ │ │ │ │ ├── ContributionsEpicReminder.tsx │ │ │ │ │ ├── ContributionsEpicReminderSignedIn.tsx │ │ │ │ │ ├── ContributionsEpicReminderSignedOut.tsx │ │ │ │ │ └── EpicButton.tsx │ │ │ │ └── utils │ │ │ │ │ ├── ophan.ts │ │ │ │ │ ├── storybook.ts │ │ │ │ │ └── threeTierChoiceCardAmounts.ts │ │ │ ├── gutters │ │ │ │ ├── GutterAsk.stories.tsx │ │ │ │ ├── GutterAsk.tsx │ │ │ │ ├── GutterAskWrapper.tsx │ │ │ │ └── utils │ │ │ │ │ └── storybook.ts │ │ │ ├── header │ │ │ │ ├── Header.stories.tsx │ │ │ │ ├── Header.tsx │ │ │ │ ├── HeaderWrapper.tsx │ │ │ │ ├── SignInPromptHeader.stories.tsx │ │ │ │ ├── SignInPromptHeader.tsx │ │ │ │ └── common │ │ │ │ │ └── HeaderDecorator.tsx │ │ │ ├── hooks │ │ │ │ ├── useArticleCountOptOut.ts │ │ │ │ ├── useChoiceCards.ts │ │ │ │ ├── useContributionsReminderEmailForm.ts │ │ │ │ ├── useContributionsReminderSignup.ts │ │ │ │ ├── useEscapeShortcut.ts │ │ │ │ └── useReminder.ts │ │ │ ├── lib │ │ │ │ ├── ReactComponent.tsx │ │ │ │ ├── articleCountOptOut.ts │ │ │ │ ├── choiceCards.ts │ │ │ │ ├── reminders.ts │ │ │ │ ├── replaceArticleCount.tsx │ │ │ │ ├── stage.ts │ │ │ │ ├── storybook.ts │ │ │ │ ├── tracking.test.ts │ │ │ │ ├── tracking.ts │ │ │ │ └── viewLog.ts │ │ │ └── shared │ │ │ │ ├── ArticleCountOptOutOverlay.tsx │ │ │ │ ├── ArticleCountOptOutPopup.tsx │ │ │ │ └── ResponsiveImage.tsx │ │ └── numbers │ │ │ ├── Eight.tsx │ │ │ ├── Five.tsx │ │ │ ├── Four.tsx │ │ │ ├── Nine.tsx │ │ │ ├── One.tsx │ │ │ ├── Seven.tsx │ │ │ ├── Six.tsx │ │ │ ├── Ten.tsx │ │ │ ├── Three.tsx │ │ │ ├── Two.tsx │ │ │ └── Zero.tsx │ ├── cricketMatch.test.ts │ ├── cricketMatch.ts │ ├── devServer │ │ ├── docs │ │ │ ├── amp.tsx │ │ │ ├── available.tsx │ │ │ ├── doc.tsx │ │ │ ├── dotcom.tsx │ │ │ ├── editionsApp.tsx │ │ │ ├── editionsCrosswords.tsx │ │ │ ├── liveApps.tsx │ │ │ ├── pages.tsx │ │ │ └── targets.tsx │ │ ├── routers │ │ │ ├── amp.ts │ │ │ ├── dotcom.ts │ │ │ ├── editionsApp.ts │ │ │ ├── liveApps.ts │ │ │ ├── pages.ts │ │ │ └── targets.ts │ │ └── send.tsx │ ├── experiments │ │ ├── ab-tests.ts │ │ ├── lib │ │ │ ├── ab-participations.test.ts │ │ │ └── ab-participations.ts │ │ ├── tests │ │ │ ├── ab-test-test.ts │ │ │ ├── ad-block-ask.ts │ │ │ ├── auxia-sign-in-gate.ts │ │ │ ├── consentless-ads.ts │ │ │ ├── integrate-ima.ts │ │ │ ├── mpu-when-no-epic.ts │ │ │ ├── optimise-spacefinder-inline.ts │ │ │ ├── sign-in-gate-main-control.ts │ │ │ ├── sign-in-gate-main-variant.ts │ │ │ └── user-benefits-api.ts │ │ └── utils.ts │ ├── footballMatch.ts │ ├── footballMatches.test.ts │ ├── footballMatches.ts │ ├── footballTables.ts │ ├── frontend │ │ ├── README.md │ │ ├── feArticle.ts │ │ ├── feCricketMatchPage.ts │ │ ├── feFootballDataPage.ts │ │ ├── feFootballMatchListPage.ts │ │ ├── feFootballMatchPage.ts │ │ ├── feFootballTablesPage.ts │ │ ├── feFront.ts │ │ ├── feTagPage.ts │ │ └── schemas │ │ │ ├── feArticle.json │ │ │ ├── feCricketMatchPage.json │ │ │ ├── feFootballMatchListPage.json │ │ │ ├── feFootballMatchPage.json │ │ │ ├── feFootballTablesPage.json │ │ │ ├── feFront.json │ │ │ └── feTagPage.json │ ├── grid.ts │ ├── layouts │ │ ├── AllEditorialNewslettersPageLayout.tsx │ │ ├── AudioLayout.tsx │ │ ├── CommentLayout.tsx │ │ ├── CrosswordLayout.tsx │ │ ├── DecideLayout.stories.tsx │ │ ├── DecideLayout.tsx │ │ ├── FrontLayout.tsx │ │ ├── FullPageInteractiveLayout.tsx │ │ ├── GalleryLayout.stories.tsx │ │ ├── GalleryLayout.tsx │ │ ├── ImmersiveLayout.tsx │ │ ├── InteractiveLayout.tsx │ │ ├── LiveLayout.tsx │ │ ├── NewsletterSignupLayout.tsx │ │ ├── PictureLayout.tsx │ │ ├── ShowcaseLayout.tsx │ │ ├── SportDataPageLayout.stories.tsx │ │ ├── SportDataPageLayout.tsx │ │ ├── StandardLayout.tsx │ │ ├── TagPageLayout.tsx │ │ └── lib │ │ │ ├── interactiveLegacyStyling.test.ts │ │ │ ├── interactiveLegacyStyling.ts │ │ │ ├── pageSkin.ts │ │ │ └── stickiness.tsx │ ├── lib │ │ ├── ArticleRenderer.tsx │ │ ├── acquisitions.test.ts │ │ ├── acquisitions.ts │ │ ├── ad-json.amp.test.ts │ │ ├── ad-json.amp.ts │ │ ├── ad-targeting.test.ts │ │ ├── ad-targeting.ts │ │ ├── adStyles.ts │ │ ├── age-warning.test.ts │ │ ├── age-warning.ts │ │ ├── alreadyVisited.ts │ │ ├── alternate-lang-links.test.ts │ │ ├── alternate-lang-links.ts │ │ ├── articleCount.ts │ │ ├── articleFormat.ts │ │ ├── assert-unreachable.ts │ │ ├── assets.test.ts │ │ ├── assets.ts │ │ ├── audio-data.ts │ │ ├── block-link.amp.ts │ │ ├── branding.test.ts │ │ ├── branding.ts │ │ ├── braze │ │ │ ├── buildBrazeMessaging.ts │ │ │ ├── checkBrazeDependencies.test.ts │ │ │ ├── checkBrazeDependencies.ts │ │ │ ├── forceBrazeMessage.ts │ │ │ ├── hasRequiredConsents.test.ts │ │ │ ├── hasRequiredConsents.ts │ │ │ ├── initialiseBraze.ts │ │ │ └── taylorReport.ts │ │ ├── bridgetApi.ts │ │ ├── buildNewsletterSignUpText.test.tsx │ │ ├── buildNewsletterSignUpText.tsx │ │ ├── byline-tokens.amp.test.ts │ │ ├── byline-tokens.amp.ts │ │ ├── byline.test.ts │ │ ├── byline.ts │ │ ├── canRenderAds.test.ts │ │ ├── canRenderAds.ts │ │ ├── cardHelpers.test.ts │ │ ├── cardHelpers.ts │ │ ├── cardWrappers.tsx │ │ ├── center.ts │ │ ├── commercial-constants.ts │ │ ├── contributions.test.ts │ │ ├── contributions.ts │ │ ├── dailyArticleCount.test.ts │ │ ├── dailyArticleCount.ts │ │ ├── decide-caption.ts │ │ ├── decide-cation.test.ts │ │ ├── decideLogo.ts │ │ ├── decideNavPillar.ts │ │ ├── decideTrail.ts │ │ ├── detect-adblock.ts │ │ ├── discussion.ts │ │ ├── discussionApi.tsx │ │ ├── discussionDateFormatter.ts │ │ ├── discussionFilters.ts │ │ ├── domUtils.ts │ │ ├── dynamicSlices.test.ts │ │ ├── dynamicSlices.tsx │ │ ├── edition.test.ts │ │ ├── edition.ts │ │ ├── emotion.tsx │ │ ├── enhance.amp.test.ts │ │ ├── enhance.amp.ts │ │ ├── errors │ │ │ └── not-renderable-in-dcr.ts │ │ ├── escapeData.test.tsx │ │ ├── escapeData.tsx │ │ ├── fetchEmail.ts │ │ ├── find-adslots.amp.test.ts │ │ ├── find-adslots.amp.ts │ │ ├── fonts-css.ts │ │ ├── formatAttrString.test.ts │ │ ├── formatAttrString.ts │ │ ├── formatCount.test.ts │ │ ├── formatCount.ts │ │ ├── formatTime.test.ts │ │ ├── formatTime.ts │ │ ├── frontsBannerAdExclusions.ts │ │ ├── get-video-id.amp.test.ts │ │ ├── get-video-id.amp.ts │ │ ├── getABUrlHash.test.ts │ │ ├── getAbUrlHash.ts │ │ ├── getBrazeUuid.ts │ │ ├── getCountryCode.ts │ │ ├── getDataLinkName.ts │ │ ├── getFrontsAdPositions.test.ts │ │ ├── getFrontsAdPositions.ts │ │ ├── getIdapiUserData.ts │ │ ├── getLiveblogAdPositions.test.ts │ │ ├── getLiveblogAdPositions.ts │ │ ├── getPrivacyFramework.ts │ │ ├── getSourceImageUrl_temp_fix.ts │ │ ├── getTagPageAdPositions.test.ts │ │ ├── getTagPageAdPositions.ts │ │ ├── getZIndex.test.ts │ │ ├── getZIndex.ts │ │ ├── hasCurrentBrazeUser.test.ts │ │ ├── hasCurrentBrazeUser.ts │ │ ├── hiddenStyles.tsx │ │ ├── hideAge.ts │ │ ├── identity-component-event.test.ts │ │ ├── identity-component-event.ts │ │ ├── identity.ts │ │ ├── image-fit.amp.test.ts │ │ ├── image-fit.amp.ts │ │ ├── image.ts │ │ ├── isLight.test.ts │ │ ├── isLight.ts │ │ ├── isServer.ts │ │ ├── isValidUrl.test.ts │ │ ├── isValidUrl.ts │ │ ├── json.ts │ │ ├── labs-constants.ts │ │ ├── labs.test.ts │ │ ├── labs.ts │ │ ├── lang.test.ts │ │ ├── lang.ts │ │ ├── layoutHelpers.ts │ │ ├── linkNotificationCount.test.ts │ │ ├── linkNotificationCount.ts │ │ ├── liveblogAdSlots.test.ts │ │ ├── liveblogAdSlots.ts │ │ ├── memoize.test.ts │ │ ├── memoize.ts │ │ ├── messagePicker.test.tsx │ │ ├── messagePicker.ts │ │ ├── mixins.ts │ │ ├── mockRESTCalls.ts │ │ ├── mockRESTCallsInJest.ts │ │ ├── newsletter-sign-up-requests.test.ts │ │ ├── newsletter-sign-up-requests.ts │ │ ├── notification.test.ts │ │ ├── notification.ts │ │ ├── ophan-helpers.test.ts │ │ ├── ophan-helpers.ts │ │ ├── parser │ │ │ ├── jsonParser.ts │ │ │ ├── parseCheckoutOutCookieData.test.ts │ │ │ └── parseCheckoutOutCookieData.ts │ │ ├── permutive.amp.test.ts │ │ ├── permutive.amp.ts │ │ ├── pillars.ts │ │ ├── polyfill.io.ts │ │ ├── querystring.test.ts │ │ ├── querystring.ts │ │ ├── readerRevenueDevUtils.ts │ │ ├── real-time-config.amp.ts │ │ ├── region-classes.amp.ts │ │ ├── renderElement.tsx │ │ ├── result.ts │ │ ├── revealStyles.ts │ │ ├── rootStyles.ts │ │ ├── scheduler.test.ts │ │ ├── scheduler.ts │ │ ├── scripts.amp.ts │ │ ├── sendTargetingParams.apps.test.ts │ │ ├── sendTargetingParams.apps.ts │ │ ├── setAutomat.ts │ │ ├── sharing-urls.ts │ │ ├── signInAfterCheckOutText.ts │ │ ├── slot-machine-flags.ts │ │ ├── srcset-utils.amp.ts │ │ ├── stringifyFileBase64.ts │ │ ├── tag-utils.amp.test.ts │ │ ├── tag-utils.amp.ts │ │ ├── themeToPillar.ts │ │ ├── thrift │ │ │ ├── nativeConnection.ts │ │ │ └── protocols.ts │ │ ├── transparentColour.test.ts │ │ ├── transparentColour.ts │ │ ├── tuple.test.ts │ │ ├── tuple.ts │ │ ├── unifyPageContent.test.tsx │ │ ├── unifyPageContent.tsx │ │ ├── useAB.ts │ │ ├── useAdBlockAsk.ts │ │ ├── useAdBlockInUse.ts │ │ ├── useAdTargeting.ts │ │ ├── useApi.ts │ │ ├── useAuthStatus.ts │ │ ├── useBraze.ts │ │ ├── useCommentCount.ts │ │ ├── useCountryCode.ts │ │ ├── useDetectAdBlock.ts │ │ ├── useEditionSwitcherBanner.ts │ │ ├── useHover.tsx │ │ ├── useHydrated.ts │ │ ├── useInterval.ts │ │ ├── useIsBridgetCompatible.test.ts │ │ ├── useIsBridgetCompatible.ts │ │ ├── useIsHorizontalScrollingSupported.ts │ │ ├── useIsInView.ts │ │ ├── useIsMyGuardianEnabled.ts │ │ ├── useMatchMedia.ts │ │ ├── useOnce.ts │ │ ├── useOnlineStatus.ts │ │ ├── usePageViewId.ts │ │ ├── useRequestSignUp.ts │ │ ├── useSDC.ts │ │ ├── useShouldAdapt.ts │ │ ├── useSignInGateSelector.ts │ │ ├── useSignInGateWillShow.ts │ │ ├── verticalDivider.ts │ │ ├── verticalDividerWithBottomOffset.ts │ │ └── withSignInGateSlot.tsx │ ├── model │ │ ├── appsLightboxImages.ts │ │ ├── article-sections.test.ts │ │ ├── article-sections.ts │ │ ├── block-schema.json │ │ ├── buildCrosswordBlock.ts │ │ ├── buildLightboxImages.ts │ │ ├── decideContainerPalette.ts │ │ ├── editions-crossword-schema.json │ │ ├── enhance-H2s.test.ts │ │ ├── enhance-H2s.ts │ │ ├── enhance-ad-placeholders.test.ts │ │ ├── enhance-ad-placeholders.ts │ │ ├── enhance-blockquotes.test.ts │ │ ├── enhance-blockquotes.ts │ │ ├── enhance-disclaimer.ts │ │ ├── enhance-dividers.test.ts │ │ ├── enhance-dividers.ts │ │ ├── enhance-dots.test.ts │ │ ├── enhance-dots.ts │ │ ├── enhance-embeds.test.ts │ │ ├── enhance-embeds.ts │ │ ├── enhance-images.test.ts │ │ ├── enhance-images.ts │ │ ├── enhance-interactive-contents-elements.ts │ │ ├── enhance-newsletters-page.ts │ │ ├── enhance-numbered-lists.test.ts │ │ ├── enhance-numbered-lists.ts │ │ ├── enhance-switches.ts │ │ ├── enhance-tweets.ts │ │ ├── enhance-videos.test.ts │ │ ├── enhance-videos.ts │ │ ├── enhanceBlocks.ts │ │ ├── enhanceCards.ts │ │ ├── enhanceCollections.ts │ │ ├── enhanceCommercialProperties.test.ts │ │ ├── enhanceCommercialProperties.ts │ │ ├── enhanceLists.test.ts │ │ ├── enhanceLists.ts │ │ ├── enhanceSnaps.ts │ │ ├── enhanceStandfirst.ts │ │ ├── enhanceTableOfContents.test.ts │ │ ├── enhanceTableOfContents.ts │ │ ├── enhanceTags.test.ts │ │ ├── enhanceTags.ts │ │ ├── enhanceTimeline.test.ts │ │ ├── enhanceTimeline.ts │ │ ├── enhanceTreats.ts │ │ ├── extract-nav.ts │ │ ├── extractTrendingTopics.test.ts │ │ ├── extractTrendingTopics.ts │ │ ├── find-pillar.test.ts │ │ ├── find-pillar.ts │ │ ├── groupCards.ts │ │ ├── groupTrailsByDates.test.ts │ │ ├── groupTrailsByDates.ts │ │ ├── guardian.ts │ │ ├── insertPromotedNewsletter.test.ts │ │ ├── insertPromotedNewsletter.ts │ │ ├── isLegacyTableOfContents.ts │ │ ├── newsletter-page-schema.json │ │ ├── pinnedPost.ts │ │ ├── sanitise.test.ts │ │ ├── sanitise.ts │ │ ├── slowOrFastByTrails.ts │ │ ├── transformDots.ts │ │ ├── unwrapHtml.test.ts │ │ ├── unwrapHtml.ts │ │ ├── validate.test.ts │ │ └── validate.ts │ ├── palette.ts │ ├── paletteDeclarations.ts │ ├── server │ │ ├── AMPExperimentCache.amp.ts │ │ ├── dev-index.html │ │ ├── handler.allEditorialNewslettersPage.web.ts │ │ ├── handler.article.amp.tsx │ │ ├── handler.article.apps.ts │ │ ├── handler.article.web.ts │ │ ├── handler.editionsCrossword.ts │ │ ├── handler.front.web.test.ts │ │ ├── handler.front.web.ts │ │ ├── handler.sportDataPage.web.test.ts │ │ ├── handler.sportDataPage.web.ts │ │ ├── htmlCrosswordPageTemplate.ts │ │ ├── htmlPageTemplate.ts │ │ ├── lib │ │ │ ├── aws │ │ │ │ ├── aws-metrics.ts │ │ │ │ └── metrics-baseline.ts │ │ │ ├── get-content-from-url.test.ts │ │ │ ├── get-content-from-url.ts │ │ │ ├── header.ts │ │ │ ├── logging-middleware.ts │ │ │ ├── logging-store.ts │ │ │ └── logging.ts │ │ ├── prout.ts │ │ ├── render.allEditorialNewslettersPage.web.tsx │ │ ├── render.article.amp.test.tsx │ │ ├── render.article.amp.tsx │ │ ├── render.article.apps.tsx │ │ ├── render.article.web.tsx │ │ ├── render.editionsCrossword.tsx │ │ ├── render.front.web.tsx │ │ ├── render.sportDataPage.web.tsx │ │ ├── server.dev.ts │ │ ├── server.prod.ts │ │ └── server.ts │ ├── sportDataPage.ts │ ├── static │ │ ├── badges │ │ │ ├── 05_july_2022_Badge.svg │ │ │ ├── 100days.svg │ │ │ ├── 18_feb_2022_Badge.svg │ │ │ ├── 56738_Badge.svg │ │ │ ├── EUReferendumBadge.svg │ │ │ ├── GE2017Badge.svg │ │ │ ├── SpecialReportJul21.svg │ │ │ ├── SpecialReportSep21.svg │ │ │ ├── anniversary200.svg │ │ │ ├── australian-election-2019.svg │ │ │ ├── australian-election-2022.svg │ │ │ ├── behind-the-lines.svg │ │ │ ├── beyondthebladebadge.svg │ │ │ ├── bias-in-britain.svg │ │ │ ├── calock.svg │ │ │ ├── cop26-badge.svg │ │ │ ├── corona-badge.svg │ │ │ ├── cricket-world-cup.svg │ │ │ ├── culture-badge.svg │ │ │ ├── dreams-interrupted.svg │ │ │ ├── election-badge-4.svg │ │ │ ├── eohk.svg │ │ │ ├── eu_election.svg │ │ │ ├── euro-2020.svg │ │ │ ├── facebookFiles.svg │ │ │ ├── futureofcities.svg │ │ │ ├── ge2019-badge.svg │ │ │ ├── general-election-2019.svg │ │ │ ├── green-blood.svg │ │ │ ├── green-recovery.svg │ │ │ ├── johnsons-promises.svg │ │ │ ├── london-versus.svg │ │ │ ├── lost-in-politics-badge.svg │ │ │ ├── midterm.svg │ │ │ ├── new-arrivals.png │ │ │ ├── newsletter-badge.svg │ │ │ ├── nhs-70.svg │ │ │ ├── pp_web.svg │ │ │ ├── rugby-world-cup.svg │ │ │ ├── spy-cops-scandal.svg │ │ │ ├── the-age-of-extinction.svg │ │ │ ├── the-empty-doorway.svg │ │ │ ├── the-implant-files.svg │ │ │ ├── the-last-chance.svg │ │ │ ├── the-new-populism.svg │ │ │ ├── the-polluters.svg │ │ │ ├── the-real-boris-johnson.svg │ │ │ ├── this-is-europe.svg │ │ │ ├── tokyo-2020.svg │ │ │ ├── uk-debt.svg │ │ │ ├── us-midterm-elections-2022.svg │ │ │ ├── winter-olympics-2022-badge.svg │ │ │ ├── womens-world-cup.svg │ │ │ ├── womens_euros_2022_badge.svg │ │ │ ├── world-cup-2018.svg │ │ │ ├── world-cup-2022.svg │ │ │ └── yemen-at-war.svg │ │ ├── css │ │ │ └── print.css │ │ ├── icons │ │ │ ├── Star.tsx │ │ │ ├── arrow-in-circle.svg │ │ │ ├── arrow-right.svg │ │ │ ├── audio │ │ │ │ ├── skip-backward-15.svg │ │ │ │ └── skip-forward-15.svg │ │ │ ├── camera.svg │ │ │ ├── chevron-left-double.svg │ │ │ ├── chevron-left-single.svg │ │ │ ├── chevron-right-double.svg │ │ │ ├── chevron-right-single.svg │ │ │ ├── clock.svg │ │ │ ├── comment.svg │ │ │ ├── down-arrow.svg │ │ │ ├── email.svg │ │ │ ├── external-link.svg │ │ │ ├── facebook.svg │ │ │ ├── gifting.svg │ │ │ ├── homescreen │ │ │ │ ├── apple-touch-icon-120.png │ │ │ │ ├── apple-touch-icon-240.png │ │ │ │ ├── apple-touch-icon-360.png │ │ │ │ ├── apple-touch-icon-512.png │ │ │ │ ├── apple-touch-icon.svg │ │ │ │ ├── roundel-114x114.png │ │ │ │ ├── roundel-152x152.png │ │ │ │ ├── roundel-192x192.png │ │ │ │ ├── roundel-256x256.png │ │ │ │ ├── roundel-512x512.png │ │ │ │ └── roundel.svg │ │ │ ├── info.svg │ │ │ ├── linked-in.svg │ │ │ ├── messenger.svg │ │ │ ├── minus.svg │ │ │ ├── newspaper.svg │ │ │ ├── plus.svg │ │ │ ├── profile.svg │ │ │ ├── quote.svg │ │ │ ├── refresh.svg │ │ │ ├── search.svg │ │ │ ├── share.svg │ │ │ ├── the-guardian-roundel.svg │ │ │ ├── tick.svg │ │ │ ├── triangle.svg │ │ │ ├── twitter-padded.svg │ │ │ ├── twitter.svg │ │ │ ├── video-icon.svg │ │ │ ├── volume-high.svg │ │ │ ├── weather │ │ │ │ ├── weather-1.svg │ │ │ │ ├── weather-11.svg │ │ │ │ ├── weather-12.svg │ │ │ │ ├── weather-13.svg │ │ │ │ ├── weather-14.svg │ │ │ │ ├── weather-15.svg │ │ │ │ ├── weather-16.svg │ │ │ │ ├── weather-17.svg │ │ │ │ ├── weather-18.svg │ │ │ │ ├── weather-19.svg │ │ │ │ ├── weather-2.svg │ │ │ │ ├── weather-20.svg │ │ │ │ ├── weather-21.svg │ │ │ │ ├── weather-22.svg │ │ │ │ ├── weather-23.svg │ │ │ │ ├── weather-24.svg │ │ │ │ ├── weather-25.svg │ │ │ │ ├── weather-26.svg │ │ │ │ ├── weather-29.svg │ │ │ │ ├── weather-3.svg │ │ │ │ ├── weather-30.svg │ │ │ │ ├── weather-31.svg │ │ │ │ ├── weather-32.svg │ │ │ │ ├── weather-33.svg │ │ │ │ ├── weather-34.svg │ │ │ │ ├── weather-35.svg │ │ │ │ ├── weather-36.svg │ │ │ │ ├── weather-37.svg │ │ │ │ ├── weather-38.svg │ │ │ │ ├── weather-39.svg │ │ │ │ ├── weather-4.svg │ │ │ │ ├── weather-40.svg │ │ │ │ ├── weather-41.svg │ │ │ │ ├── weather-42.svg │ │ │ │ ├── weather-43.svg │ │ │ │ ├── weather-44.svg │ │ │ │ ├── weather-5.svg │ │ │ │ ├── weather-6.svg │ │ │ │ ├── weather-7.svg │ │ │ │ └── weather-8.svg │ │ │ ├── whatsapp.svg │ │ │ └── x.svg │ │ ├── js │ │ │ └── curl-with-js-and-domReady.js │ │ ├── logos │ │ │ ├── hands.png │ │ │ └── the-guardian-labs.svg │ │ └── manifest.json │ └── types │ │ ├── article.amp.tsx │ │ ├── article.ts │ │ ├── badge.ts │ │ ├── blocks.ts │ │ ├── branding.ts │ │ ├── commercial.ts │ │ ├── config.ts │ │ ├── configContext.ts │ │ ├── content.ts │ │ ├── editionsCrossword.ts │ │ ├── footer.ts │ │ ├── front.ts │ │ ├── frontend.ts │ │ ├── layout.ts │ │ ├── liveBlog.ts │ │ ├── mainMedia.ts │ │ ├── matchReport.ts │ │ ├── newslettersPage.ts │ │ ├── onwards.ts │ │ ├── palette.ts │ │ ├── renderingTarget.ts │ │ ├── sentry.ts │ │ ├── sport.ts │ │ ├── tag.ts │ │ ├── tagPage.ts │ │ ├── territory.ts │ │ └── trails.ts ├── stories │ └── generated │ │ ├── Card.stories.tsx │ │ └── CardReadme.stories.jsx ├── stylelint.config.mjs ├── tsconfig.build.json ├── tsconfig.json ├── webpack.config.mjs ├── webpack │ ├── .swcrc.json │ ├── @types │ │ ├── webpack-filter-warnings-plugin │ │ │ └── index.d.ts │ │ └── webpack-messages │ │ │ └── index.d.ts │ ├── browser-targets.js │ ├── browser-targets.test.ts │ ├── bundles.js │ ├── svg.cjs │ ├── webpack.config.client.js │ ├── webpack.config.dev-server.js │ ├── webpack.config.js │ └── webpack.config.server.js └── window.guardian.ts ├── package.json ├── patches └── webpack-manifest-plugin@5.0.0.patch ├── pnpm-lock.yaml ├── pnpm-workspace.yaml └── scripts ├── deno ├── README.md ├── bots.ts ├── deno.json ├── deno.lock ├── eslint.ts ├── github.ts ├── iframe-titles.ts ├── json.ts └── thrasher-tracker.ts ├── env ├── check-dependencies-mismatches.mjs ├── check-node └── check-package-manager ├── log.js └── postinstall.sh /.editorconfig: -------------------------------------------------------------------------------- 1 | ; This file is for unifying the coding style for different editors and IDEs 2 | ; See editorconfig.org 3 | 4 | ; top-most EditorConfig file 5 | root = true 6 | 7 | [*] 8 | indent_style = tab 9 | indent_size = 4 10 | end_of_line = lf 11 | charset = utf-8 12 | trim_trailing_whitespace = true 13 | insert_final_newline = true 14 | 15 | [package.json] 16 | indent_size = 2 17 | 18 | [makefile] 19 | indent_style = tab 20 | 21 | [*.{yml,yaml}] 22 | indent_size = 2 23 | indent_style = space 24 | -------------------------------------------------------------------------------- /.github/actions/setup-node-env/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Setup Environment' 2 | description: 'Sets up Node.js environment and installs dependencies' 3 | 4 | runs: 5 | using: 'composite' 6 | steps: 7 | - run: npm install --global corepack@0.31.0 8 | shell: bash 9 | 10 | - run: corepack enable 11 | shell: bash 12 | 13 | - uses: actions/setup-node@v4 14 | with: 15 | node-version-file: '.nvmrc' 16 | cache: 'pnpm' 17 | 18 | - run: pnpm install --frozen-lockfile 19 | shell: bash 20 | -------------------------------------------------------------------------------- /.github/labeler.yml: -------------------------------------------------------------------------------- 1 | # https://github.com/marketplace/actions/labeler 2 | 3 | dotcom-rendering: 4 | - changed-files: 5 | - any-glob-to-any-file: 'dotcom-rendering/**/*' 6 | apps-rendering: 7 | - changed-files: 8 | - any-glob-to-any-file: 'apps-rendering/**/*' 9 | -------------------------------------------------------------------------------- /.github/workflows/build-check.yml: -------------------------------------------------------------------------------- 1 | name: DCR Build Check 2 | on: 3 | push: 4 | paths-ignore: 5 | - 'apps-rendering/**' 6 | - 'dotcom-rendering/docs/**' 7 | 8 | jobs: 9 | build_check: 10 | name: DCR Build Check 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout code 14 | uses: actions/checkout@v4 15 | 16 | - name: Set up Node environment 17 | uses: ./.github/actions/setup-node-env 18 | 19 | - name: Generate production build 20 | run: make build 21 | working-directory: dotcom-rendering 22 | 23 | - name: Validate Build 24 | run: make buildCheck 25 | working-directory: dotcom-rendering 26 | -------------------------------------------------------------------------------- /.github/workflows/deno.yml: -------------------------------------------------------------------------------- 1 | name: 🦕 Deno health 2 | on: 3 | pull_request: 4 | paths: 5 | - 'scripts/deno/**' 6 | 7 | jobs: 8 | deno: 9 | name: 🦕 Deno health 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | 14 | # https://github.com/denoland/setup-deno#latest-stable-for-a-major 15 | - uses: denoland/setup-deno@v1 16 | with: 17 | deno-version: v1.44 18 | 19 | - name: Format 20 | run: deno fmt scripts/deno 21 | 22 | - name: Lint 23 | run: deno lint scripts/deno 24 | 25 | - name: Type-check 26 | run: deno check scripts/deno/**.ts 27 | -------------------------------------------------------------------------------- /.github/workflows/jest.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | 4 | jobs: 5 | jest: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v4 9 | 10 | - name: Set up Node environment 11 | uses: ./.github/actions/setup-node-env 12 | 13 | - name: Run Jest 14 | run: CI=true pnpm test 15 | working-directory: dotcom-rendering 16 | -------------------------------------------------------------------------------- /.github/workflows/labeler.yml: -------------------------------------------------------------------------------- 1 | name: 'Pull Request Labeler' 2 | on: 3 | - pull_request_target 4 | 5 | jobs: 6 | triage: 7 | permissions: 8 | contents: read 9 | pull-requests: write 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/labeler@v5 13 | with: 14 | repo-token: '${{ secrets.GITHUB_TOKEN }}' 15 | sync-labels: true # remove redundant labels after a change 16 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | 4 | jobs: 5 | check: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v4 9 | 10 | - name: Set up Node environment 11 | uses: ./.github/actions/setup-node-env 12 | 13 | - name: Lint Project 14 | run: make lint-project 15 | working-directory: dotcom-rendering 16 | 17 | - name: Lint 18 | run: make lint 19 | working-directory: dotcom-rendering 20 | 21 | - name: Stylelint 22 | run: make stylelint 23 | working-directory: dotcom-rendering 24 | -------------------------------------------------------------------------------- /.github/workflows/permissions-advisor.yml: -------------------------------------------------------------------------------- 1 | name: Permissions Advisor 2 | 3 | permissions: 4 | actions: read 5 | 6 | on: 7 | workflow_dispatch: 8 | inputs: 9 | name: 10 | description: 'The name of the workflow file to analyze' 11 | required: true 12 | type: string 13 | count: 14 | description: 'How many last runs to analyze' 15 | required: false 16 | type: number 17 | default: 5 18 | 19 | jobs: 20 | advisor: 21 | runs-on: ubuntu-latest 22 | steps: 23 | - uses: GitHubSecurityLab/actions-permissions/advisor@v1 24 | with: 25 | name: ${{ inputs.name }} 26 | count: ${{ inputs.count }} 27 | -------------------------------------------------------------------------------- /.github/workflows/prettier.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | 4 | jobs: 5 | check: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v4 9 | 10 | - name: Set up Node environment 11 | uses: ./.github/actions/setup-node-env 12 | 13 | - name: Prettier check 14 | run: pnpm prettier:check 15 | -------------------------------------------------------------------------------- /.github/workflows/schema-check.yml: -------------------------------------------------------------------------------- 1 | name: DCR Schema Check 2 | on: 3 | push: 4 | paths-ignore: 5 | - 'apps-rendering/**' 6 | - 'dotcom-rendering/docs/**' 7 | 8 | jobs: 9 | build_check: 10 | name: DCR Schema Check 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout code 14 | uses: actions/checkout@v4 15 | 16 | - name: Set up Node environment 17 | uses: ./.github/actions/setup-node-env 18 | 19 | - name: Run check-schemas script 20 | run: make check-schemas 21 | working-directory: dotcom-rendering 22 | -------------------------------------------------------------------------------- /.github/workflows/stories-check.yml: -------------------------------------------------------------------------------- 1 | name: DCR Stories Check 2 | on: 3 | push: 4 | paths-ignore: 5 | - 'apps-rendering/**' 6 | - 'dotcom-rendering/docs/**' 7 | 8 | jobs: 9 | build_check: 10 | name: DCR Stories Check 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout code 14 | uses: actions/checkout@v4 15 | 16 | - name: Set up Node environment 17 | uses: ./.github/actions/setup-node-env 18 | 19 | - name: Run check-stories script 20 | run: make check-stories 21 | working-directory: dotcom-rendering 22 | -------------------------------------------------------------------------------- /.github/workflows/typescript.yml: -------------------------------------------------------------------------------- 1 | name: DCR typescript 🕵‍♀ 2 | on: 3 | push: 4 | paths-ignore: 5 | - 'apps-rendering/**' 6 | - 'dotcom-rendering/docs/**' 7 | 8 | jobs: 9 | typescript: 10 | name: Typescript 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | 15 | - name: Set up Node environment 16 | uses: ./.github/actions/setup-node-env 17 | 18 | - name: Check typescript 19 | run: pnpm tsc 20 | working-directory: dotcom-rendering 21 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | # don't run this on CI 2 | # https://typicode.github.io/husky/#/?id=with-env-variables 3 | [ -n "$CI" ] && exit 0 4 | 5 | pnpm lint-staged 6 | -------------------------------------------------------------------------------- /.husky/pre-push: -------------------------------------------------------------------------------- 1 | currentBranch="$(git rev-parse --abbrev-ref HEAD)" 2 | 3 | if [[ $currentBranch == "main" ]] 4 | then 5 | echo "⚠️ You should not push to the \`main\` branch" 6 | exit 1 7 | fi 8 | 9 | cd ./$(dirname "$0")/../dotcom-rendering 10 | make tsc 11 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | save-prefix='' 2 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 22.14.0 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist 2 | deno 3 | .nvmrc 4 | pnpm-lock.yaml 5 | 6 | # generated files 7 | dotcom-rendering/src/model/*-schema.json 8 | dotcom-rendering/src/frontend/schemas 9 | dotcom-rendering/stories/generated 10 | 11 | # specific files 12 | /**/*/curl-with-js-and-domReady.js 13 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | "@guardian/prettier" 2 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "esbenp.prettier-vscode", 4 | "wix.vscode-import-cost", 5 | "orta.vscode-jest", 6 | "editorconfig.editorconfig", 7 | "dbaeumer.vscode-eslint", 8 | "stkb.rewrap", 9 | "styled-components.vscode-styled-components", 10 | "stylelint.vscode-stylelint", 11 | "eamodio.gitlens", 12 | "streetsidesoftware.code-spell-checker", 13 | "denoland.vscode-deno", 14 | "redhat.vscode-yaml" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /.vscode/settings.json.required: -------------------------------------------------------------------------------- 1 | // Required VS Code settings for this project. 2 | // Copy these to .vscode/settings.json to apply them to your editor – but don't commit it! 3 | // https://github.com/guardian/recommendations/blob/main/VSCode.md#do-not-commit-vscode 4 | { 5 | "deno.enablePaths": ["scripts/deno"], 6 | "deno.lint": true, 7 | "deno.unstable": false, 8 | "typescript.tsdk": "node_modules/typescript/lib", 9 | "git.branchProtection": ["main"], 10 | "eslint.workingDirectories": ["./dotcom-rendering"] 11 | } 12 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Welcome to the the Guardian's Apps & Web rendering platforms 2 | 3 | Read our [Code of conduct](./CODE_OF_CONDUCT.md) to help keep things approachable and respectful. 4 | 5 | Interested in our web rendering platform? [Start here ➡️](./dotcom-rendering/docs/contributing/README.md) 6 | 7 | Interested in our apps rendering platform? [Start here ➡️](./apps-rendering/README.md) 8 | -------------------------------------------------------------------------------- /apps-rendering/.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | indent_size = 4 -------------------------------------------------------------------------------- /apps-rendering/.eslintignore: -------------------------------------------------------------------------------- 1 | *.test.ts 2 | node_modules 3 | api-models 4 | webpack.config.ts 5 | cdk.out 6 | -------------------------------------------------------------------------------- /apps-rendering/.gitignore: -------------------------------------------------------------------------------- 1 | ### Node template 2 | # Logs 3 | logs 4 | *.log 5 | npm-debug.log* 6 | 7 | # Dependency directories 8 | node_modules 9 | 10 | # IDE files 11 | .idea 12 | .vscode/* 13 | !.vscode/extensions.json 14 | .metals/ 15 | .bloop/ 16 | project/.bloop/ 17 | project/metals.sbt 18 | .bsp/ 19 | 20 | # System files 21 | .DS_Store 22 | 23 | # Built files 24 | dist 25 | 26 | # Istanbul/Jest code coverage 27 | coverage 28 | 29 | # CDK asset staging directory 30 | .cdk.staging 31 | cdk.out 32 | -------------------------------------------------------------------------------- /apps-rendering/assets/fonts/GHGuardianHeadline-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guardian/dotcom-rendering/51a37f970de19d02a8b8db3177563450cb274049/apps-rendering/assets/fonts/GHGuardianHeadline-Bold.ttf -------------------------------------------------------------------------------- /apps-rendering/assets/fonts/GHGuardianHeadline-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guardian/dotcom-rendering/51a37f970de19d02a8b8db3177563450cb274049/apps-rendering/assets/fonts/GHGuardianHeadline-BoldItalic.ttf -------------------------------------------------------------------------------- /apps-rendering/assets/fonts/GHGuardianHeadline-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guardian/dotcom-rendering/51a37f970de19d02a8b8db3177563450cb274049/apps-rendering/assets/fonts/GHGuardianHeadline-Light.ttf -------------------------------------------------------------------------------- /apps-rendering/assets/fonts/GHGuardianHeadline-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guardian/dotcom-rendering/51a37f970de19d02a8b8db3177563450cb274049/apps-rendering/assets/fonts/GHGuardianHeadline-LightItalic.ttf -------------------------------------------------------------------------------- /apps-rendering/assets/fonts/GHGuardianHeadline-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guardian/dotcom-rendering/51a37f970de19d02a8b8db3177563450cb274049/apps-rendering/assets/fonts/GHGuardianHeadline-Medium.ttf -------------------------------------------------------------------------------- /apps-rendering/assets/fonts/GHGuardianHeadline-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guardian/dotcom-rendering/51a37f970de19d02a8b8db3177563450cb274049/apps-rendering/assets/fonts/GHGuardianHeadline-MediumItalic.ttf -------------------------------------------------------------------------------- /apps-rendering/assets/fonts/GHGuardianHeadline-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guardian/dotcom-rendering/51a37f970de19d02a8b8db3177563450cb274049/apps-rendering/assets/fonts/GHGuardianHeadline-Regular.ttf -------------------------------------------------------------------------------- /apps-rendering/assets/fonts/GHGuardianHeadline-RegularItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guardian/dotcom-rendering/51a37f970de19d02a8b8db3177563450cb274049/apps-rendering/assets/fonts/GHGuardianHeadline-RegularItalic.ttf -------------------------------------------------------------------------------- /apps-rendering/assets/fonts/GHGuardianHeadline-Semibold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guardian/dotcom-rendering/51a37f970de19d02a8b8db3177563450cb274049/apps-rendering/assets/fonts/GHGuardianHeadline-Semibold.ttf -------------------------------------------------------------------------------- /apps-rendering/assets/fonts/GHGuardianHeadline-SemiboldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guardian/dotcom-rendering/51a37f970de19d02a8b8db3177563450cb274049/apps-rendering/assets/fonts/GHGuardianHeadline-SemiboldItalic.ttf -------------------------------------------------------------------------------- /apps-rendering/assets/fonts/GuardianTextEgyptian-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guardian/dotcom-rendering/51a37f970de19d02a8b8db3177563450cb274049/apps-rendering/assets/fonts/GuardianTextEgyptian-Bold.ttf -------------------------------------------------------------------------------- /apps-rendering/assets/fonts/GuardianTextEgyptian-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guardian/dotcom-rendering/51a37f970de19d02a8b8db3177563450cb274049/apps-rendering/assets/fonts/GuardianTextEgyptian-BoldItalic.ttf -------------------------------------------------------------------------------- /apps-rendering/assets/fonts/GuardianTextEgyptian-Reg.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guardian/dotcom-rendering/51a37f970de19d02a8b8db3177563450cb274049/apps-rendering/assets/fonts/GuardianTextEgyptian-Reg.ttf -------------------------------------------------------------------------------- /apps-rendering/assets/fonts/GuardianTextEgyptian-RegItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guardian/dotcom-rendering/51a37f970de19d02a8b8db3177563450cb274049/apps-rendering/assets/fonts/GuardianTextEgyptian-RegItalic.ttf -------------------------------------------------------------------------------- /apps-rendering/assets/fonts/GuardianTextSans-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guardian/dotcom-rendering/51a37f970de19d02a8b8db3177563450cb274049/apps-rendering/assets/fonts/GuardianTextSans-Bold.ttf -------------------------------------------------------------------------------- /apps-rendering/assets/fonts/GuardianTextSans-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guardian/dotcom-rendering/51a37f970de19d02a8b8db3177563450cb274049/apps-rendering/assets/fonts/GuardianTextSans-BoldItalic.ttf -------------------------------------------------------------------------------- /apps-rendering/assets/fonts/GuardianTextSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guardian/dotcom-rendering/51a37f970de19d02a8b8db3177563450cb274049/apps-rendering/assets/fonts/GuardianTextSans-Regular.ttf -------------------------------------------------------------------------------- /apps-rendering/assets/fonts/GuardianTextSans-RegularItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guardian/dotcom-rendering/51a37f970de19d02a8b8db3177563450cb274049/apps-rendering/assets/fonts/GuardianTextSans-RegularItalic.ttf -------------------------------------------------------------------------------- /apps-rendering/cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "pnpm tsx cdk/bin/cdk.ts", 3 | "context": { 4 | "aws-cdk:enableDiffNoFail": "true", 5 | "@aws-cdk/core:stackRelativeExports": "true" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /apps-rendering/cdk/README.md: -------------------------------------------------------------------------------- 1 | # Infrastructure 2 | 3 | This directory defines the components to be deployed to AWS 4 | -------------------------------------------------------------------------------- /apps-rendering/config/jestSetup.js: -------------------------------------------------------------------------------- 1 | jest.mock('@guardian/cdk/lib/constants/tracking-tag'); 2 | 3 | /** 4 | * Some tests use a JSDOM Jest environment. It appears that TextEncoder is not 5 | * available globally, and so we need to enable it here. 6 | * See https://github.com/jestjs/jest/issues/9983 7 | */ 8 | global.TextEncoder = require('util').TextEncoder; 9 | -------------------------------------------------------------------------------- /apps-rendering/config/jestglobalSetup.js: -------------------------------------------------------------------------------- 1 | // Set environment variable for timezone to have 2 | // consistent timezone no matter which machine 3 | // the tests are running from 4 | export default () => { 5 | process.env.TZ = 'Europe/London'; 6 | }; 7 | -------------------------------------------------------------------------------- /apps-rendering/config/tsconfig.client.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig", 3 | "compilerOptions": { 4 | // Output latest features; allow babel to handle browser targeting 5 | "target": "es2020" 6 | }, 7 | "include": ["../src/client/*"] 8 | } 9 | -------------------------------------------------------------------------------- /apps-rendering/config/tsconfig.server.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig", 3 | "compilerOptions": { 4 | "target": "es2019" 5 | }, 6 | "files": ["../src/server/server.ts"] 7 | } 8 | -------------------------------------------------------------------------------- /apps-rendering/config/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig", 3 | "compilerOptions": { 4 | "allowJs": true 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /apps-rendering/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Why are you doing this? 2 | 3 | 9 | 10 | ## Changes 11 | 12 | - Change 1 13 | - Change 2 14 | 15 | ## Screenshots 16 | 17 | | Before | After | 18 | | ---------------------------- | ---------------------------- | 19 | | | | 20 | -------------------------------------------------------------------------------- /apps-rendering/src/articleFormat.test.ts: -------------------------------------------------------------------------------- 1 | // ----- Imports ----- // 2 | 3 | import { ArticleDesign, ArticleDisplay, Pillar } from 'articleFormat'; 4 | import { formatToString } from 'articleFormat'; 5 | 6 | // ----- Tests ----- // 7 | 8 | describe('formatToString', () => { 9 | it('creates a string describing ArticleFormat', () => { 10 | const format = formatToString({ 11 | design: ArticleDesign.Standard, 12 | display: ArticleDisplay.Immersive, 13 | theme: Pillar.Culture, 14 | }); 15 | 16 | expect(format).toBe( 17 | 'Design: Standard, Display: Immersive, Theme: Culture', 18 | ); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /apps-rendering/src/bodyElementKind.ts: -------------------------------------------------------------------------------- 1 | // ----- Types ----- // 2 | 3 | const enum ElementKind { 4 | Text, 5 | Image, 6 | Pullquote, 7 | Interactive, 8 | RichLink, 9 | Tweet, 10 | Embed, 11 | Callout, 12 | LiveEvent, 13 | InteractiveAtom, 14 | ExplainerAtom, 15 | MediaAtom, 16 | GuideAtom, 17 | QandaAtom, 18 | ProfileAtom, 19 | TimelineAtom, 20 | ChartAtom, 21 | AudioAtom, 22 | KnowledgeQuizAtom, 23 | PersonalityQuizAtom, 24 | NewsletterSignUp, 25 | HeadingTwo, 26 | HeadingThree, 27 | SpecialReportAltAtom, 28 | } 29 | 30 | // ----- Exports ----- // 31 | 32 | export { ElementKind }; 33 | -------------------------------------------------------------------------------- /apps-rendering/src/components/Audio/index.tsx: -------------------------------------------------------------------------------- 1 | // ----- Imports ----- // 2 | 3 | import { css } from '@emotion/react'; 4 | 5 | // ----- Component ----- // 6 | 7 | interface Props { 8 | src: string; 9 | width: number; 10 | height: number; 11 | } 12 | 13 | const audioStyles = css` 14 | border: none; 15 | `; 16 | 17 | const Audio = ({ src, width, height }: Props) => ( 18 |