diff --git a/index.d.ts b/index.d.ts index 97e20d86bbb..0da0af8d4fc 100644 --- a/index.d.ts +++ b/index.d.ts @@ -12,23 +12,23 @@ type CAPIPillar = RealPillars | FakePillars; // CAPIDesign is what CAPI might give us but we only want to use a subset of these (Design) // https://github.com/guardian/content-api-scala-client/blob/master/client/src/main/scala/com.gu.contentapi.client/utils/DesignType.scala type CAPIDesign = - | 'Article' - | 'Media' - | 'Review' - | 'Analysis' - | 'Comment' - | 'Feature' - | 'Live' - | 'Recipe' - | 'MatchReport' - | 'Interview' - | 'GuardianView' - | 'Quiz' - | 'AdvertisementFeature' - | 'PhotoEssay' - | 'Immersive' - | 'SpecialReport' - | 'GuardianLabs' + | 'Article' + | 'Media' + | 'Review' + | 'Analysis' + | 'Comment' + | 'Feature' + | 'Live' + | 'Recipe' + | 'MatchReport' + | 'Interview' + | 'GuardianView' + | 'Quiz' + | 'AdvertisementFeature' + | 'PhotoEssay' + | 'Immersive' + | 'SpecialReport' + | 'GuardianLabs'; type Design = import('@guardian/types').Design; type Theme = import('@guardian/types').Theme; @@ -41,345 +41,347 @@ type Pillar = Theme; // eslint-disable-next-line @typescript-eslint/no-explicit-any type DesignTypesObj = { [key in Design]: any }; +type Palette = { [key: string]: any }; + type Edition = 'UK' | 'US' | 'INT' | 'AU'; type SharePlatform = - | 'facebook' - | 'twitter' - | 'email' - | 'whatsApp' - | 'pinterest' - | 'linkedIn' - | 'messenger'; + | 'facebook' + | 'twitter' + | 'email' + | 'whatsApp' + | 'pinterest' + | 'linkedIn' + | 'messenger'; // shared type declarations interface SimpleLinkType { - url: string; - title: string; + url: string; + title: string; } interface AdTargetParam { - name: string; - value: string | string[]; + name: string; + value: string | string[]; } interface AdTargeting { - adUnit: string; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - customParams: { [key: string]: any }; + adUnit: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + customParams: { [key: string]: any }; } interface SectionNielsenAPI { - name: string; - apiID: string; + name: string; + apiID: string; } interface EditionCommercialProperties { - adTargeting: AdTargetParam[]; - branding?: Branding; + adTargeting: AdTargetParam[]; + branding?: Branding; } type CommercialProperties = { [E in Edition]: EditionCommercialProperties }; interface Branding { - brandingType?: { name: string }; - sponsorName: string; - logo: { - src: string; - link: string; - label: string; - dimensions: { width: number; height: number }; - }; - aboutThisLink: string; - logoForDarkBackground?: { - src: string; - dimensions: { width: number; height: number }; - link: string; - label: string; - }; + brandingType?: { name: string }; + sponsorName: string; + logo: { + src: string; + link: string; + label: string; + dimensions: { width: number; height: number }; + }; + aboutThisLink: string; + logoForDarkBackground?: { + src: string; + dimensions: { width: number; height: number }; + link: string; + label: string; + }; } interface CAPILinkType extends SimpleLinkType { - longTitle: string; - children?: LinkType[]; - mobileOnly?: boolean; - pillar?: CAPIPillar; - more?: boolean; + longTitle: string; + children?: LinkType[]; + mobileOnly?: boolean; + pillar?: CAPIPillar; + more?: boolean; } interface LinkType extends SimpleLinkType { - longTitle: string; - children?: LinkType[]; - mobileOnly?: boolean; - pillar?: Pillar; - more?: boolean; + longTitle: string; + children?: LinkType[]; + mobileOnly?: boolean; + pillar?: Pillar; + more?: boolean; } interface CAPIPillarType extends CAPILinkType { - pillar: CAPIPillar; + pillar: CAPIPillar; } interface PillarType extends LinkType { - pillar: Pillar; + pillar: Pillar; } interface MoreType extends LinkType { - more: true; + more: true; } interface ReaderRevenueCategories { - contribute: string; - subscribe: string; - support: string; - gifting: string; + contribute: string; + subscribe: string; + support: string; + gifting: string; } type ReaderRevenueCategory = 'contribute' | 'subscribe' | 'support'; interface ReaderRevenuePositions { - header: ReaderRevenueCategories; - footer: ReaderRevenueCategories; - sideMenu: ReaderRevenueCategories; - ampHeader: ReaderRevenueCategories; - ampFooter: ReaderRevenueCategories; + header: ReaderRevenueCategories; + footer: ReaderRevenueCategories; + sideMenu: ReaderRevenueCategories; + ampHeader: ReaderRevenueCategories; + ampFooter: ReaderRevenueCategories; } type ReaderRevenuePosition = - | 'header' - | 'footer' - | 'sideMenu' - | 'ampHeader' - | 'ampFooter'; + | 'header' + | 'footer' + | 'sideMenu' + | 'ampHeader' + | 'ampFooter'; interface BaseNavType { - otherLinks: MoreType; - brandExtensions: LinkType[]; - currentNavLink: string; - subNavSections?: SubNavType; - readerRevenueLinks: ReaderRevenuePositions; + otherLinks: MoreType; + brandExtensions: LinkType[]; + currentNavLink: string; + subNavSections?: SubNavType; + readerRevenueLinks: ReaderRevenuePositions; } interface NavType extends BaseNavType { - pillars: PillarType[]; + pillars: PillarType[]; } interface CAPINavType extends BaseNavType { - pillars: CAPIPillarType[]; + pillars: CAPIPillarType[]; } interface SubNavBrowserType { - currentNavLink: string; - subNavSections?: SubNavType; + currentNavLink: string; + subNavSections?: SubNavType; } interface SubNavType { - parent?: LinkType; - links: LinkType[]; + parent?: LinkType; + links: LinkType[]; } interface AuthorType { - byline?: string; - twitterHandle?: string; - email?: string; + byline?: string; + twitterHandle?: string; + email?: string; } interface Block { - id: string; - elements: CAPIElement[]; - blockCreatedOn?: number; - blockCreatedOnDisplay?: string; - blockLastUpdated?: number; - blockLastUpdatedDisplay?: string; - title?: string; - blockFirstPublished?: number; - blockFirstPublishedDisplay?: string; - primaryDateLine: string; - secondaryDateLine: string; + id: string; + elements: CAPIElement[]; + blockCreatedOn?: number; + blockCreatedOnDisplay?: string; + blockLastUpdated?: number; + blockLastUpdatedDisplay?: string; + title?: string; + blockFirstPublished?: number; + blockFirstPublishedDisplay?: string; + primaryDateLine: string; + secondaryDateLine: string; } interface Pagination { - currentPage: number; - totalPages: number; - newest?: string; - newer?: string; - oldest?: string; - older?: string; + currentPage: number; + totalPages: number; + newest?: string; + newer?: string; + oldest?: string; + older?: string; } interface FooterLink { - text: string; - url: string; - dataLinkName: string; - extraClasses?: string; + text: string; + url: string; + dataLinkName: string; + extraClasses?: string; } interface FooterType { - footerLinks: FooterLink[][]; + footerLinks: FooterLink[][]; } type ContentType = - | 'article' - | 'network' - | 'section' - | 'imageContent' - | 'interactive' - | 'gallery' - | 'video' - | 'audio' - | 'liveBlog' - | 'tag' - | 'index' - | 'crossword' - | 'survey' - | 'signup' - | 'userid'; + | 'article' + | 'network' + | 'section' + | 'imageContent' + | 'interactive' + | 'gallery' + | 'video' + | 'audio' + | 'liveBlog' + | 'tag' + | 'index' + | 'crossword' + | 'survey' + | 'signup' + | 'userid'; type PageTypeType = { - hasShowcaseMainElement: boolean; - isFront: boolean; - isLiveblog: boolean; - isMinuteArticle: boolean; - isPaidContent: boolean; - isPreview: boolean; - isSensitive: boolean; + hasShowcaseMainElement: boolean; + isFront: boolean; + isLiveblog: boolean; + isMinuteArticle: boolean; + isPaidContent: boolean; + isPreview: boolean; + isSensitive: boolean; }; // WARNING: run `gen-schema` task if changing this to update the associated JSON // schema definition. interface CAPIType { - headline: string; - standfirst: string; - webTitle: string; - mainMediaElements: CAPIElement[]; - main: string; - keyEvents: Block[]; - blocks: Block[]; - pagination?: Pagination; - author: AuthorType; - - /** - * @TJS-format date-time - */ - webPublicationDate: string; - - webPublicationDateDisplay: string; - editionLongForm: string; - editionId: Edition; - pageId: string; - version: number; // TODO: check who uses? - tags: TagType[]; - pillar: CAPIPillar; - isImmersive: boolean; - sectionLabel: string; - sectionUrl: string; - sectionName?: string; - subMetaSectionLinks: SimpleLinkType[]; - subMetaKeywordLinks: SimpleLinkType[]; - shouldHideAds: boolean; - isAdFreeUser: boolean; - openGraphData: { [key: string]: string }; - twitterData: { [key: string]: string }; - webURL: string; - linkedData: object[]; - config: ConfigType; - // The CAPI object sent from frontend can have designType Immersive. We force this to be Article - // in decideDesignType but need to allow the type here before then - designType: CAPIDesign; - showBottomSocialButtons: boolean; - shouldHideReaderRevenue: boolean; - - // AMP specific (for now) - guardianBaseURL: string; - contentType: string; - hasRelated: boolean; - publication: string; // TODO: check who uses? - hasStoryPackage: boolean; - beaconURL: string; - isCommentable: boolean; - commercialProperties: CommercialProperties; - starRating?: number; - trailText: string; - badge?: BadgeType; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - nav: any; // as not extracting directly into NavType here for now (nav stuff is getting moved out) - - pageFooter: FooterType; - - contributionsServiceUrl: string; - slotMachineFlags?: string; - - pageType: PageTypeType; - - matchUrl?: string; + headline: string; + standfirst: string; + webTitle: string; + mainMediaElements: CAPIElement[]; + main: string; + keyEvents: Block[]; + blocks: Block[]; + pagination?: Pagination; + author: AuthorType; + + /** + * @TJS-format date-time + */ + webPublicationDate: string; + + webPublicationDateDisplay: string; + editionLongForm: string; + editionId: Edition; + pageId: string; + version: number; // TODO: check who uses? + tags: TagType[]; + pillar: CAPIPillar; + isImmersive: boolean; + sectionLabel: string; + sectionUrl: string; + sectionName?: string; + subMetaSectionLinks: SimpleLinkType[]; + subMetaKeywordLinks: SimpleLinkType[]; + shouldHideAds: boolean; + isAdFreeUser: boolean; + openGraphData: { [key: string]: string }; + twitterData: { [key: string]: string }; + webURL: string; + linkedData: object[]; + config: ConfigType; + // The CAPI object sent from frontend can have designType Immersive. We force this to be Article + // in decideDesignType but need to allow the type here before then + designType: CAPIDesign; + showBottomSocialButtons: boolean; + shouldHideReaderRevenue: boolean; + + // AMP specific (for now) + guardianBaseURL: string; + contentType: string; + hasRelated: boolean; + publication: string; // TODO: check who uses? + hasStoryPackage: boolean; + beaconURL: string; + isCommentable: boolean; + commercialProperties: CommercialProperties; + starRating?: number; + trailText: string; + badge?: BadgeType; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + nav: any; // as not extracting directly into NavType here for now (nav stuff is getting moved out) + + pageFooter: FooterType; + + contributionsServiceUrl: string; + slotMachineFlags?: string; + + pageType: PageTypeType; + + matchUrl?: string; } type CAPIBrowserType = { - // The CAPI object sent from frontend can have designType Immersive. We force this to be Article - // in decideDesignType but need to allow the type here before then - designType: CAPIDesign; - pillar: CAPIPillar; - config: ConfigTypeBrowser; - richLinks: RichLinkBlockElement[]; - editionId: Edition; - editionLongForm: string; - contentType: string; - sectionName?: string; - shouldHideReaderRevenue: boolean; - pageType: { - isMinuteArticle: boolean; - isPaidContent: boolean; - hasShowcaseMainElement: boolean; - }; - hasRelated: boolean; - hasStoryPackage: boolean; - shouldHideAds: boolean; - isAdFreeUser: boolean; - pageId: string; - tags: TagType[]; - isCommentable: boolean; - nav: { - readerRevenueLinks: { - footer: ReaderRevenueCategories; - header: ReaderRevenueCategories; - }; - }; - contributionsServiceUrl: string; - isImmersive: boolean; - isPhotoEssay: boolean; - matchUrl?: string; - callouts: CalloutBlockElement[]; - qandaAtoms: QABlockElement[]; - guideAtoms: GuideAtomBlockElement[]; - profileAtoms: ProfileAtomBlockElement[]; - timelineAtoms: TimelineBlockElement[]; - chartAtoms: ChartAtomBlockElement[]; - audioAtoms: AudioAtomBlockElement[]; - youtubeBlockElement: YoutubeBlockElement[]; - youtubeMainMediaBlockElement: YoutubeBlockElement[]; - quizAtoms: QuizAtomBlockElement[]; + // The CAPI object sent from frontend can have designType Immersive. We force this to be Article + // in decideDesignType but need to allow the type here before then + designType: CAPIDesign; + pillar: CAPIPillar; + config: ConfigTypeBrowser; + richLinks: RichLinkBlockElement[]; + editionId: Edition; + editionLongForm: string; + contentType: string; + sectionName?: string; + shouldHideReaderRevenue: boolean; + pageType: { + isMinuteArticle: boolean; + isPaidContent: boolean; + hasShowcaseMainElement: boolean; + }; + hasRelated: boolean; + hasStoryPackage: boolean; + shouldHideAds: boolean; + isAdFreeUser: boolean; + pageId: string; + tags: TagType[]; + isCommentable: boolean; + nav: { + readerRevenueLinks: { + footer: ReaderRevenueCategories; + header: ReaderRevenueCategories; + }; + }; + contributionsServiceUrl: string; + isImmersive: boolean; + isPhotoEssay: boolean; + matchUrl?: string; + callouts: CalloutBlockElement[]; + qandaAtoms: QABlockElement[]; + guideAtoms: GuideAtomBlockElement[]; + profileAtoms: ProfileAtomBlockElement[]; + timelineAtoms: TimelineBlockElement[]; + chartAtoms: ChartAtomBlockElement[]; + audioAtoms: AudioAtomBlockElement[]; + youtubeBlockElement: YoutubeBlockElement[]; + youtubeMainMediaBlockElement: YoutubeBlockElement[]; + quizAtoms: QuizAtomBlockElement[]; }; interface TagType { - id: string; - type: string; - title: string; - twitterHandle?: string; - paidContentType?: string; - bylineImageUrl?: string; + id: string; + type: string; + title: string; + twitterHandle?: string; + paidContentType?: string; + bylineImageUrl?: string; } interface BadgeType { - seriesTag: string; - imageUrl: string; + seriesTag: string; + imageUrl: string; } // Defines a prefix to be used with a headline (e.g. 'Live /') interface KickerType { - text: string; - design: Design; - pillar: Theme; - showPulsingDot?: boolean; - showSlash?: boolean; - inCard?: boolean; // True when headline is showing inside a card (used to handle coloured backgrounds) + text: string; + design: Design; + pillar: Theme; + showPulsingDot?: boolean; + showSlash?: boolean; + inCard?: boolean; // True when headline is showing inside a card (used to handle coloured backgrounds) } type ImagePositionType = 'left' | 'top' | 'right'; @@ -387,8 +389,8 @@ type ImagePositionType = 'left' | 'top' | 'right'; type SmallHeadlineSize = 'tiny' | 'small' | 'medium' | 'large'; type AvatarType = { - src: string; - alt: string; + src: string; + alt: string; }; type MediaType = 'Video' | 'Audio' | 'Gallery'; @@ -425,128 +427,128 @@ type ImageSizeType = 'small' | 'medium' | 'large' | 'jumbo'; type CardPercentageType = '25%' | '33%' | '50%' | '67%' | '75%' | '100%'; type HeadlineLink = { - to: string; // the href for the anchor tag - visitedColour?: string; // a custom colour for the :visited state - preventFocus?: boolean; // if true, stop the link from being tabbable and focusable + to: string; // the href for the anchor tag + visitedColour?: string; // a custom colour for the :visited state + preventFocus?: boolean; // if true, stop the link from being tabbable and focusable }; interface LinkHeadlineType { - design: Design; - headlineText: string; // The text shown - pillar: Theme; // Used to colour the headline (dark) and the kicker (main) - showUnderline?: boolean; // Some headlines have text-decoration underlined when hovered - kickerText?: string; - showPulsingDot?: boolean; - showSlash?: boolean; - showQuotes?: boolean; // When true the QuoteIcon is shown - size?: SmallHeadlineSize; - link?: HeadlineLink; // An optional link object configures if/how the component renders an anchor tag - byline?: string; + design: Design; + headlineText: string; // The text shown + pillar: Theme; // Used to colour the headline (dark) and the kicker (main) + showUnderline?: boolean; // Some headlines have text-decoration underlined when hovered + kickerText?: string; + showPulsingDot?: boolean; + showSlash?: boolean; + showQuotes?: boolean; // When true the QuoteIcon is shown + size?: SmallHeadlineSize; + link?: HeadlineLink; // An optional link object configures if/how the component renders an anchor tag + byline?: string; } interface CardHeadlineType { - headlineText: string; // The text shown - design: Design; // Used to decide when to add type specific styles - pillar: Theme; // Used to colour the headline (dark) and the kicker (main) - kickerText?: string; - showPulsingDot?: boolean; - showSlash?: boolean; - showQuotes?: boolean; // Even with design !== Comment, a piece can be opinion - size?: SmallHeadlineSize; - byline?: string; - showByline?: boolean; + headlineText: string; // The text shown + design: Design; // Used to decide when to add type specific styles + pillar: Theme; // Used to colour the headline (dark) and the kicker (main) + kickerText?: string; + showPulsingDot?: boolean; + showSlash?: boolean; + showQuotes?: boolean; // Even with design !== Comment, a piece can be opinion + size?: SmallHeadlineSize; + byline?: string; + showByline?: boolean; } type UserBadge = { - name: string; + name: string; }; type UserProfile = { - userId: string; - displayName: string; - webUrl: string; - apiUrl: string; - avatar: string; - secureAvatarUrl: string; - badge: UserBadge[]; - - // only included from /profile/me endpoint - privateFields?: { - canPostComment: boolean; - isPremoderated: boolean; - hasCommented: boolean; - }; + userId: string; + displayName: string; + webUrl: string; + apiUrl: string; + avatar: string; + secureAvatarUrl: string; + badge: UserBadge[]; + + // only included from /profile/me endpoint + privateFields?: { + canPostComment: boolean; + isPremoderated: boolean; + hasCommented: boolean; + }; }; /** * Football */ type TeamType = { - id: string; - name: string; - players: PlayerType[]; - possession: number; - shotsOn: number; - shotsOff: number; - corners: number; - fouls: number; - colours: string; - score: number; - crest: string; - scorers: string[]; + id: string; + name: string; + players: PlayerType[]; + possession: number; + shotsOn: number; + shotsOff: number; + corners: number; + fouls: number; + colours: string; + score: number; + crest: string; + scorers: string[]; }; type PlayerType = { - id: string; - name: string; - position: string; - lastName: string; - substitute: boolean; - timeOnPitch: string; - shirtNumber: string; - events: EventType[]; + id: string; + name: string; + position: string; + lastName: string; + substitute: boolean; + timeOnPitch: string; + shirtNumber: string; + events: EventType[]; }; type EventType = { - eventTime: string; // minutes - eventType: 'substitution' | 'dismissal' | 'booking'; + eventTime: string; // minutes + eventType: 'substitution' | 'dismissal' | 'booking'; }; /** * Onwards */ type OnwardsType = { - heading: string; - trails: TrailType[]; - description?: string; - url?: string; - ophanComponentName: OphanComponentName; - pillar: Theme; + heading: string; + trails: TrailType[]; + description?: string; + url?: string; + ophanComponentName: OphanComponentName; + pillar: Theme; }; type OphanComponentName = - | 'series' - | 'more-on-this-story' - | 'related-stories' - | 'related-content' - | 'more-media-in-section' - | 'more-galleries' - | 'curated-content' - | 'default-onwards'; // We should never see this in the analytics data! + | 'series' + | 'more-on-this-story' + | 'related-stories' + | 'related-content' + | 'more-media-in-section' + | 'more-galleries' + | 'curated-content' + | 'default-onwards'; // We should never see this in the analytics data! interface CommercialConfigType { - isPaidContent?: boolean; - pageId: string; - webPublicationDate?: number; - headline?: string; - author?: string; - keywords?: string; - section?: string; - edition?: string; - series?: string; - toneIds?: string; - contentType: string; - ampIframeUrl: string; + isPaidContent?: boolean; + pageId: string; + webPublicationDate?: number; + headline?: string; + author?: string; + keywords?: string; + section?: string; + edition?: string; + series?: string; + toneIds?: string; + contentType: string; + ampIframeUrl: string; } /** @@ -556,94 +558,94 @@ interface CommercialConfigType { * this data could eventually be defined in dotcom-rendering */ interface ConfigType extends CommercialConfigType { - ajaxUrl: string; - sentryPublicApiKey: string; - sentryHost: string; - dcrSentryDsn: string; - switches: { [key: string]: boolean }; - abTests: { [key: string]: string }; - dfpAccountId: string; - commercialBundleUrl: string; - revisionNumber: string; - shortUrlId: string; - isDev?: boolean; - googletagUrl: string; - stage: string; - frontendAssetsFullURL: string; - hbImpl: object | string; - adUnit: string; - isSensitive: boolean; - videoDuration: number; - edition: string; - section: string; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - sharedAdTargeting: { [key: string]: any }; - isPaidContent?: boolean; - keywordIds: string; - showRelatedContent: boolean; - shouldHideReaderRevenue?: boolean; - idApiUrl: string; - discussionApiUrl: string; - discussionD2Uid: string; - discussionApiClientHeader: string; - isPhotoEssay: boolean; - references?: { [key: string]: string }[]; - host?: string; - idUrl?: string; - mmaUrl?: string; - brazeApiKey?: string; - ipsosTag?: string; + ajaxUrl: string; + sentryPublicApiKey: string; + sentryHost: string; + dcrSentryDsn: string; + switches: { [key: string]: boolean }; + abTests: { [key: string]: string }; + dfpAccountId: string; + commercialBundleUrl: string; + revisionNumber: string; + shortUrlId: string; + isDev?: boolean; + googletagUrl: string; + stage: string; + frontendAssetsFullURL: string; + hbImpl: object | string; + adUnit: string; + isSensitive: boolean; + videoDuration: number; + edition: string; + section: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + sharedAdTargeting: { [key: string]: any }; + isPaidContent?: boolean; + keywordIds: string; + showRelatedContent: boolean; + shouldHideReaderRevenue?: boolean; + idApiUrl: string; + discussionApiUrl: string; + discussionD2Uid: string; + discussionApiClientHeader: string; + isPhotoEssay: boolean; + references?: { [key: string]: string }[]; + host?: string; + idUrl?: string; + mmaUrl?: string; + brazeApiKey?: string; + ipsosTag?: string; } interface ConfigTypeBrowser { - frontendAssetsFullURL: string; - isDev: boolean; - ajaxUrl: string; - shortUrlId: string; - pageId: string; - isPaidContent: boolean; - showRelatedContent: boolean; - keywordIds: string; - ampIframeUrl: string; - ampPrebid: boolean; - permutive: boolean; - enableSentryReporting: boolean; - enableDiscussionSwitch: boolean; - slotBodyEnd: boolean; - isSensitive: boolean; - videoDuration: number; - edition: string; - section: string; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - sharedAdTargeting: { [key: string]: any }; - adUnit: string; - idApiUrl: string; - discussionApiUrl: string; - discussionD2Uid: string; - discussionApiClientHeader: string; - dcrSentryDsn: string; - remoteBanner: boolean; - ausMoment2020Header: boolean; - switches: CAPIType['config']['switches']; - host?: string; - idUrl?: string; - mmaUrl?: string; + frontendAssetsFullURL: string; + isDev: boolean; + ajaxUrl: string; + shortUrlId: string; + pageId: string; + isPaidContent: boolean; + showRelatedContent: boolean; + keywordIds: string; + ampIframeUrl: string; + ampPrebid: boolean; + permutive: boolean; + enableSentryReporting: boolean; + enableDiscussionSwitch: boolean; + slotBodyEnd: boolean; + isSensitive: boolean; + videoDuration: number; + edition: string; + section: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + sharedAdTargeting: { [key: string]: any }; + adUnit: string; + idApiUrl: string; + discussionApiUrl: string; + discussionD2Uid: string; + discussionApiClientHeader: string; + dcrSentryDsn: string; + remoteBanner: boolean; + ausMoment2020Header: boolean; + switches: CAPIType['config']['switches']; + host?: string; + idUrl?: string; + mmaUrl?: string; } interface GADataType { - pillar: CAPIPillar; - webTitle: string; - section: string; - contentType: string; - commissioningDesks: string; - contentId: string; - authorIds: string; - keywordIds: string; - toneIds: string; - seriesId: string; - isHosted: string; - edition: Edition; - beaconUrl: string; + pillar: CAPIPillar; + webTitle: string; + section: string; + contentType: string; + commissioningDesks: string; + contentId: string; + authorIds: string; + keywordIds: string; + toneIds: string; + seriesId: string; + isHosted: string; + edition: Edition; + beaconUrl: string; } // ----------------- // @@ -651,58 +653,58 @@ interface GADataType { // ----------------- // interface DCRServerDocumentData { - page: string; - site: string; - CAPI: CAPIType; - NAV: NavType; - GA: GADataType; - linkedData: object; + page: string; + site: string; + CAPI: CAPIType; + NAV: NavType; + GA: GADataType; + linkedData: object; } interface DCRBrowserDocumentData { - page: string; - site: string; - CAPI: CAPIBrowserType; - NAV: SubNavBrowserType; - GA: GADataType; - linkedData: object; + page: string; + site: string; + CAPI: CAPIBrowserType; + NAV: SubNavBrowserType; + GA: GADataType; + linkedData: object; } interface Props { - data: DCRServerDocumentData; // Do not fall to the tempation to rename 'data' into something else + data: DCRServerDocumentData; // Do not fall to the tempation to rename 'data' into something else } type IslandType = - | 'reader-revenue-links-header' - | 'sub-nav-root' - | 'edition-root' - | 'most-viewed-right' - | 'share-count-root' - | 'comment-count-root' - | 'most-viewed-footer' - | 'reader-revenue-links-footer' - | 'slot-body-end' - | 'bottom-banner' - | 'onwards-upper-whensignedin' - | 'onwards-upper-whensignedout' - | 'onwards-lower-whensignedin' - | 'onwards-lower-whensignedout' - | 'rich-link' - | 'links-root' - | 'match-nav' - | 'match-stats' - | 'callout' - | 'comments' - | 'quiz-atom' - | 'qanda-atom' - | 'guide-atom' - | 'profile-atom' - | 'timeline-atom' - | 'sign-in-gate' - | 'audio-atom' - | 'youtube-block' - | 'youtube-block-main-media' - | 'chart-atom'; + | 'reader-revenue-links-header' + | 'sub-nav-root' + | 'edition-root' + | 'most-viewed-right' + | 'share-count-root' + | 'comment-count-root' + | 'most-viewed-footer' + | 'reader-revenue-links-footer' + | 'slot-body-end' + | 'bottom-banner' + | 'onwards-upper-whensignedin' + | 'onwards-upper-whensignedout' + | 'onwards-lower-whensignedin' + | 'onwards-lower-whensignedout' + | 'rich-link' + | 'links-root' + | 'match-nav' + | 'match-stats' + | 'callout' + | 'comments' + | 'quiz-atom' + | 'qanda-atom' + | 'guide-atom' + | 'profile-atom' + | 'timeline-atom' + | 'sign-in-gate' + | 'audio-atom' + | 'youtube-block' + | 'youtube-block-main-media' + | 'chart-atom'; // All Components that are loaded with loadable // should be added here, this is the chunk name as @@ -730,7 +732,6 @@ interface RichLinkBlockLoadable extends ComponentNameChunkMap { type LoadableComponents = [EditionDropdownLoadable, YoutubeBlockLoadable, RichLinkBlockLoadable] interface BaseTrailType { - url: string; headline: string; isLiveBlog: boolean; @@ -749,66 +750,66 @@ interface BaseTrailType { linkText?: string; } interface TrailType extends BaseTrailType { - design: Design; - pillar: Theme; + design: Design; + pillar: Theme; } interface CAPITrailType extends BaseTrailType { - designType: CAPIDesign; - pillar: CAPIPillar; + designType: CAPIDesign; + pillar: CAPIPillar; } interface TrailTabType { - heading: string; - trails: TrailType[]; + heading: string; + trails: TrailType[]; } interface CAPITrailTabType { - heading: string; - trails: CAPITrailType[]; + heading: string; + trails: CAPITrailType[]; } interface MostViewedFooterPayloadType { - tabs: CAPITrailTabType[]; - mostCommented: CAPITrailType; - mostShared: CAPITrailType; + tabs: CAPITrailTabType[]; + mostCommented: CAPITrailType; + mostShared: CAPITrailType; } // ---------- // AdSlots // // ---------- type AdSlotType = - | 'right' - | 'top-above-nav' - | 'mostpop' - | 'merchandising-high' - | 'merchandising' - | 'comments'; + | 'right' + | 'top-above-nav' + | 'mostpop' + | 'merchandising-high' + | 'merchandising' + | 'comments'; // ------------------------------ // 3rd party type declarations // // ------------------------------ /* eslint-disable @typescript-eslint/no-explicit-any */ declare module 'emotion-server' { - export const extractCritical: any; + export const extractCritical: any; } declare module 'dompurify' { - const createDOMPurify: any; - export default createDOMPurify; + const createDOMPurify: any; + export default createDOMPurify; } declare module 'compose-function' { - const compose: any; - export default compose; + const compose: any; + export default compose; } declare module 'minify-css-string' { - const minifyCSSString: any; - export default minifyCSSString; + const minifyCSSString: any; + export default minifyCSSString; } declare module 'chromatic/isChromatic'; /* eslint-enable @typescript-eslint/no-explicit-any */ declare module 'dynamic-import-polyfill' { - export const initialize: any; + export const initialize: any; } // ------------------------------------- // @@ -816,44 +817,44 @@ declare module 'dynamic-import-polyfill' { // ------------------------------------- // declare namespace JSX { - /* eslint-disable @typescript-eslint/no-explicit-any */ - interface IntrinsicElements { - 'amp-experiment': any; - 'amp-sidebar': any; - 'amp-accordion': any; - 'amp-img': any; - 'amp-twitter': any; - 'amp-list': any; - 'amp-vimeo': any; - 'amp-facebook': any; - 'amp-video': any; - 'amp-instagram': any; - 'amp-soundcloud': any; - 'amp-iframe': any; - 'amp-analytics': any; - 'amp-pixel': any; - 'amp-ad': any; - 'amp-youtube': any; - 'amp-geo': any; - 'amp-consent': any; - 'amp-live-list': any; - 'amp-audio': any; - 'amp-embed': any; - } - /* eslint-enable @typescript-eslint/no-explicit-any */ + /* eslint-disable @typescript-eslint/no-explicit-any */ + interface IntrinsicElements { + 'amp-experiment': any; + 'amp-sidebar': any; + 'amp-accordion': any; + 'amp-img': any; + 'amp-twitter': any; + 'amp-list': any; + 'amp-vimeo': any; + 'amp-facebook': any; + 'amp-video': any; + 'amp-instagram': any; + 'amp-soundcloud': any; + 'amp-iframe': any; + 'amp-analytics': any; + 'amp-pixel': any; + 'amp-ad': any; + 'amp-youtube': any; + 'amp-geo': any; + 'amp-consent': any; + 'amp-live-list': any; + 'amp-audio': any; + 'amp-embed': any; + } + /* eslint-enable @typescript-eslint/no-explicit-any */ } // SVG handling declare module '*.svg' { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const content: any; - export default content; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const content: any; + export default content; } // Extend PerformanceEntry from lib.dom.ts with current 'In Draft' properties (to allow access as use in browsers that support) // lib.dom.ts: https://microsoft.github.io/PowerBI-JavaScript/interfaces/_node_modules_typedoc_node_modules_typescript_lib_lib_dom_d_.performanceentry.html // Draft: https://wicg.github.io/element-timing/#sec-performance-element-timing interface PerformanceEntry { - loadTime: number; - renderTime: number; + loadTime: number; + renderTime: number; } diff --git a/src/lib/pillars.ts b/src/lib/pillars.ts index 62a635fd51e..4310d508c17 100644 --- a/src/lib/pillars.ts +++ b/src/lib/pillars.ts @@ -1,4 +1,5 @@ -import { Special, Pillar, Theme } from '@guardian/types'; +import { Special, Pillar } from '@guardian/types'; +import type { Theme } from '@guardian/types'; import { news as _news, diff --git a/src/web/components/App.tsx b/src/web/components/App.tsx index 4ebcd9ac1ed..edc784c20d3 100644 --- a/src/web/components/App.tsx +++ b/src/web/components/App.tsx @@ -43,7 +43,8 @@ import { getCountryCode } from '@frontend/web/lib/getCountryCode'; import { getUser } from '@root/src/web/lib/getUser'; import { FocusStyleManager } from '@guardian/src-foundations/utils'; -import { Display, Design, Format } from '@guardian/types'; +import { Display, Design } from '@guardian/types'; +import type { Format } from '@guardian/types'; import { incrementAlreadyVisited } from '@root/src/web/lib/alreadyVisited'; import { incrementDailyArticleCount } from '@frontend/web/lib/dailyArticleCount'; import { getArticleCountConsent } from '@frontend/web/lib/contributions'; diff --git a/src/web/components/ArticleBody.tsx b/src/web/components/ArticleBody.tsx index 9363152d481..fba3bd9be97 100644 --- a/src/web/components/ArticleBody.tsx +++ b/src/web/components/ArticleBody.tsx @@ -6,7 +6,8 @@ import { headline } from '@guardian/src-foundations/typography'; import { between } from '@guardian/src-foundations/mq'; import { pillarMap, pillarPalette } from '@root/src/lib/pillars'; import { ArticleRenderer } from '@root/src/web/lib/ArticleRenderer'; -import { Display, Pillar, Format } from '@guardian/types'; +import { Display, Pillar } from '@guardian/types'; +import type { Format } from '@guardian/types'; type Props = { format: Format; diff --git a/src/web/components/ArticleHeadline.stories.tsx b/src/web/components/ArticleHeadline.stories.tsx index e029302dbad..3c824672a24 100644 --- a/src/web/components/ArticleHeadline.stories.tsx +++ b/src/web/components/ArticleHeadline.stories.tsx @@ -10,6 +10,7 @@ import { ArticleContainer } from './ArticleContainer'; import { MainMedia } from './MainMedia'; import { Standfirst } from './Standfirst'; import { mainMediaElements } from './ArticleHeadline.mocks'; +import { decidePalette } from '../lib/decidePalette'; export default { component: ArticleHeadline, @@ -26,6 +27,11 @@ export const ArticleStory = () => ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( x; @@ -87,10 +87,6 @@ const underlinedStyles = css` background-origin: content-box; `; -const colourStyles = (colour?: string) => css` - color: ${colour && colour}; -`; - const displayBlock = css` display: block; `; @@ -110,7 +106,6 @@ const shiftSlightly = css` const invertedStyles = css` position: relative; - color: white; white-space: pre-wrap; padding-bottom: ${space[1]}px; padding-right: ${space[1]}px; @@ -140,7 +135,6 @@ const blackBackground = css` `; const invertedText = css` - color: white; white-space: pre-wrap; padding-bottom: ${space[1]}px; padding-right: ${space[1]}px; @@ -200,6 +194,7 @@ export const ArticleHeadline = ({ pillar, tags, byline, + palette, }: Props) => { switch (display) { case Display.Immersive: { @@ -223,7 +218,15 @@ export const ArticleHeadline = ({ case Design.GuardianView: return ( <> -

+

{curly(headlineString)}

{byline && ( @@ -241,7 +244,15 @@ export const ArticleHeadline = ({ return ( // Immersive headlines with main media present, are large and inverted with // a black background -

+

{curly(headlineString)} @@ -278,7 +291,14 @@ export const ArticleHeadline = ({ case Design.GuardianView: return ( <> -

+

{curly(headlineString)}

{byline && ( @@ -294,7 +314,15 @@ export const ArticleHeadline = ({ ); case Design.Analysis: return ( -

+

{curly(headlineString)}

); @@ -311,6 +339,9 @@ export const ArticleHeadline = ({ invertedFont, invertedWrapper, zIndex, + css` + color: ${palette.text.headline}; + `, )} > +

{curly(headlineString)}

); diff --git a/src/web/components/ArticleMeta.tsx b/src/web/components/ArticleMeta.tsx index 0a55252035e..d9bd3858ffb 100644 --- a/src/web/components/ArticleMeta.tsx +++ b/src/web/components/ArticleMeta.tsx @@ -8,7 +8,8 @@ import { Counts } from '@root/src/web/components/Counts'; import { getSharingUrls } from '@root/src/lib/sharing-urls'; import { Branding } from '@root/src/web/components/Branding'; -import { Display, Design, Format } from '@guardian/types'; +import { Display, Design } from '@guardian/types'; +import type { Format } from '@guardian/types'; import { SharingIcons } from './ShareIcons'; import { Dateline } from './Dateline'; diff --git a/src/web/components/Avatar.stories.tsx b/src/web/components/Avatar.stories.tsx index 8cfad015240..55ca2530609 100644 --- a/src/web/components/Avatar.stories.tsx +++ b/src/web/components/Avatar.stories.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import { Design, Display, Format, Pillar } from '@guardian/types'; +import { Design, Display, Pillar } from '@guardian/types'; +import type { Format } from '@guardian/types'; import { Avatar } from './Avatar'; diff --git a/src/web/components/Avatar.tsx b/src/web/components/Avatar.tsx index be74886a6e0..bda8e3834a2 100644 --- a/src/web/components/Avatar.tsx +++ b/src/web/components/Avatar.tsx @@ -1,7 +1,8 @@ import React from 'react'; import { css, cx } from 'emotion'; -import { Format, Pillar } from '@guardian/types'; +import { Pillar } from '@guardian/types'; +import type { Format } from '@guardian/types'; import { pillarPalette } from '@frontend/lib/pillars'; diff --git a/src/web/components/MostViewed/MostViewedFooter/SecondTierItem.tsx b/src/web/components/MostViewed/MostViewedFooter/SecondTierItem.tsx index 338f3fbb1dc..8350236821d 100644 --- a/src/web/components/MostViewed/MostViewedFooter/SecondTierItem.tsx +++ b/src/web/components/MostViewed/MostViewedFooter/SecondTierItem.tsx @@ -1,7 +1,8 @@ import React from 'react'; import { css } from 'emotion'; -import { Design, Pillar, Format, Display } from '@guardian/types'; +import { Design, Pillar, Display } from '@guardian/types'; +import type { Format } from '@guardian/types'; import { border, neutral, text } from '@guardian/src-foundations/palette'; import { headline } from '@guardian/src-foundations/typography'; import { from } from '@guardian/src-foundations/mq'; diff --git a/src/web/components/RichLink.tsx b/src/web/components/RichLink.tsx index 86bae16f181..2059f24f449 100644 --- a/src/web/components/RichLink.tsx +++ b/src/web/components/RichLink.tsx @@ -8,7 +8,8 @@ import { } from '@guardian/src-foundations/palette'; import { headline, textSans } from '@guardian/src-foundations/typography'; import { from, until, between } from '@guardian/src-foundations/mq'; -import { Design, Display, Format, Pillar } from '@guardian/types'; +import { Design, Display, Pillar } from '@guardian/types'; +import type { Format } from '@guardian/types'; import ArrowInCircle from '@frontend/static/icons/arrow-in-circle.svg'; diff --git a/src/web/components/SubNav/SubNav.tsx b/src/web/components/SubNav/SubNav.tsx index ca7b9603236..220a2eb252a 100644 --- a/src/web/components/SubNav/SubNav.tsx +++ b/src/web/components/SubNav/SubNav.tsx @@ -4,7 +4,7 @@ import { css, cx } from 'emotion'; import { text, news, neutral } from '@guardian/src-foundations/palette'; import { textSans } from '@guardian/src-foundations/typography'; import { from } from '@guardian/src-foundations/mq'; -import { Format } from '@guardian/types'; +import type { Format } from '@guardian/types'; import { pillarPalette, pillarMap } from '@root/src/lib/pillars'; diff --git a/src/web/layouts/CommentLayout.tsx b/src/web/layouts/CommentLayout.tsx index cd2835d875c..f5f651b2bc0 100644 --- a/src/web/layouts/CommentLayout.tsx +++ b/src/web/layouts/CommentLayout.tsx @@ -250,9 +250,10 @@ interface Props { CAPI: CAPIType; NAV: NavType; format: Format; + palette: Palette; } -export const CommentLayout = ({ CAPI, NAV, format }: Props) => { +export const CommentLayout = ({ CAPI, NAV, format, palette }: Props) => { const { config: { isPaidContent, host }, } = CAPI; @@ -396,6 +397,7 @@ export const CommentLayout = ({ CAPI, NAV, format }: Props) => { { pillar: CAPI.pillar, design, }); - const format: Format = { display, design, theme: pillar, }; + const palette = decidePalette(format); switch (display) { case Display.Immersive: { @@ -39,6 +41,7 @@ export const DecideLayout = ({ CAPI, NAV }: Props) => { ); @@ -47,6 +50,7 @@ export const DecideLayout = ({ CAPI, NAV }: Props) => { ); @@ -57,11 +61,21 @@ export const DecideLayout = ({ CAPI, NAV }: Props) => { case Design.Comment: case Design.GuardianView: return ( - + ); default: return ( - + ); } } @@ -71,11 +85,21 @@ export const DecideLayout = ({ CAPI, NAV }: Props) => { case Design.Comment: case Design.GuardianView: return ( - + ); default: return ( - + ); } } diff --git a/src/web/layouts/ImmersiveLayout.tsx b/src/web/layouts/ImmersiveLayout.tsx index ef05b1d07d6..ccf4fa04a80 100644 --- a/src/web/layouts/ImmersiveLayout.tsx +++ b/src/web/layouts/ImmersiveLayout.tsx @@ -8,7 +8,8 @@ import { } from '@guardian/src-foundations/palette'; import { from, until } from '@guardian/src-foundations/mq'; import { space } from '@guardian/src-foundations'; -import { Design, Format } from '@guardian/types'; +import { Design } from '@guardian/types'; +import type { Format } from '@guardian/types'; import { ArticleBody } from '@root/src/web/components/ArticleBody'; import { RightColumn } from '@root/src/web/components/RightColumn'; @@ -175,6 +176,7 @@ interface Props { CAPI: CAPIType; NAV: NavType; format: Format; + palette: Palette; } const decideCaption = (mainMedia: ImageBlockElement): string => { @@ -191,7 +193,7 @@ const decideCaption = (mainMedia: ImageBlockElement): string => { return caption.join(' '); }; -export const ImmersiveLayout = ({ CAPI, NAV, format }: Props) => { +export const ImmersiveLayout = ({ CAPI, NAV, format, palette }: Props) => { const { config: { isPaidContent, host }, } = CAPI; @@ -358,6 +360,7 @@ export const ImmersiveLayout = ({ CAPI, NAV, format }: Props) => { { { +export const ShowcaseLayout = ({ CAPI, NAV, format, palette }: Props) => { const { config: { isPaidContent, host }, } = CAPI; @@ -345,6 +347,7 @@ export const ShowcaseLayout = ({ CAPI, NAV, format }: Props) => { { +export const StandardLayout = ({ CAPI, NAV, format, palette }: Props) => { const { config: { isPaidContent, host }, } = CAPI; @@ -439,6 +441,7 @@ export const StandardLayout = ({ CAPI, NAV, format }: Props) => { pillar={format.theme} tags={CAPI.tags} byline={CAPI.author.byline} + palette={palette} /> {age && ( { + switch (format.display) { + case Display.Immersive: + switch (format.design) { + case Design.PrintShop: + return text.primary; + default: + return neutral[100]; + } + case Display.Showcase: + case Display.Standard: { + switch (format.design) { + case Design.Review: + case Design.Recipe: + case Design.Feature: + return pillarPalette[format.theme].dark; + case Design.Interview: + return neutral[100]; + default: + return text.primary; + } + } + default: + return text.primary; + } +}; + +export const decidePalette = (format: Format) => { + return { + text: { + headline: textHeadline(format), + }, + }; +};