Skip to content

Commit 58e9af8

Browse files
committed
feat: add support for RecommendedList
This component will display a collection of `Recommended` items. The initial use case is the onward journey in Partner Content. The single `Recommended` component remains the primary pattern on FT.com, as testing shows that one prominent recommendation performs better.
1 parent 1e271e9 commit 58e9af8

File tree

5 files changed

+123
-6
lines changed

5 files changed

+123
-6
lines changed

README.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ type BodyBlock =
102102
| ThematicBreak
103103
| Table
104104
| Recommended
105+
| RecommendedList
105106
| Tweet
106107
| Video
107108
| YoutubeVideo
@@ -433,8 +434,23 @@ interface Recommended extends Node {
433434

434435
_non normative note:_ historically, recommended links used to be a list of up to
435436
three content items. Testing later showed that having one more prominent link
436-
was more engaging, and Spark (and therefore content-tree)now only supports that
437-
use case.
437+
was more engaging. Only use `RecommendedList` if you explicitly need to display multiple links.
438+
439+
440+
### `RecommendedList`
441+
442+
443+
```ts
444+
interface RecommendedList extends Node {
445+
type: "recommended-list";
446+
heading?: string;
447+
children: Recommended[];
448+
}
449+
```
450+
451+
- RecommendedList represents a collection of Recommended items selected by editorial.
452+
- The `heading`, when present, is used where the purpose of the link is more
453+
specific than being "Related Content"
438454

439455
#### Teaser types
440456

content-tree.d.ts

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export declare namespace ContentTree {
2-
type BodyBlock = Paragraph | Heading | ImageSet | Flourish | BigNumber | CustomCodeComponent | Layout | List | Blockquote | Pullquote | ScrollyBlock | ThematicBreak | Table | Recommended | Tweet | Video | YoutubeVideo | Text;
2+
type BodyBlock = Paragraph | Heading | ImageSet | Flourish | BigNumber | CustomCodeComponent | Layout | List | Blockquote | Pullquote | ScrollyBlock | ThematicBreak | Table | Recommended | RecommendedList | Tweet | Video | YoutubeVideo | Text;
33
type LayoutWidth = "auto" | "in-line" | "inset-left" | "inset-right" | "full-bleed" | "full-grid" | "mid-grid" | "full-width";
44
type Phrasing = Text | Break | Strong | Emphasis | Strikethrough | Link;
55
interface Node {
@@ -107,6 +107,11 @@ export declare namespace ContentTree {
107107
teaserTitleOverride?: string;
108108
teaser: Teaser;
109109
}
110+
interface RecommendedList extends Node {
111+
type: "recommended-list";
112+
heading?: string;
113+
children: Recommended[];
114+
}
110115
type TeaserConcept = {
111116
apiUrl: string;
112117
directType: string;
@@ -274,7 +279,7 @@ export declare namespace ContentTree {
274279
attributes: CustomCodeComponentAttributes;
275280
}
276281
namespace full {
277-
type BodyBlock = Paragraph | Heading | ImageSet | Flourish | BigNumber | CustomCodeComponent | Layout | List | Blockquote | Pullquote | ScrollyBlock | ThematicBreak | Table | Recommended | Tweet | Video | YoutubeVideo | Text;
282+
type BodyBlock = Paragraph | Heading | ImageSet | Flourish | BigNumber | CustomCodeComponent | Layout | List | Blockquote | Pullquote | ScrollyBlock | ThematicBreak | Table | Recommended | RecommendedList | Tweet | Video | YoutubeVideo | Text;
278283
type LayoutWidth = "auto" | "in-line" | "inset-left" | "inset-right" | "full-bleed" | "full-grid" | "mid-grid" | "full-width";
279284
type Phrasing = Text | Break | Strong | Emphasis | Strikethrough | Link;
280285
interface Node {
@@ -382,6 +387,11 @@ export declare namespace ContentTree {
382387
teaserTitleOverride?: string;
383388
teaser: Teaser;
384389
}
390+
interface RecommendedList extends Node {
391+
type: "recommended-list";
392+
heading?: string;
393+
children: Recommended[];
394+
}
385395
type TeaserConcept = {
386396
apiUrl: string;
387397
directType: string;
@@ -550,7 +560,7 @@ export declare namespace ContentTree {
550560
}
551561
}
552562
namespace transit {
553-
type BodyBlock = Paragraph | Heading | ImageSet | Flourish | BigNumber | CustomCodeComponent | Layout | List | Blockquote | Pullquote | ScrollyBlock | ThematicBreak | Table | Recommended | Tweet | Video | YoutubeVideo | Text;
563+
type BodyBlock = Paragraph | Heading | ImageSet | Flourish | BigNumber | CustomCodeComponent | Layout | List | Blockquote | Pullquote | ScrollyBlock | ThematicBreak | Table | Recommended | RecommendedList | Tweet | Video | YoutubeVideo | Text;
554564
type LayoutWidth = "auto" | "in-line" | "inset-left" | "inset-right" | "full-bleed" | "full-grid" | "mid-grid" | "full-width";
555565
type Phrasing = Text | Break | Strong | Emphasis | Strikethrough | Link;
556566
interface Node {
@@ -656,6 +666,11 @@ export declare namespace ContentTree {
656666
heading?: string;
657667
teaserTitleOverride?: string;
658668
}
669+
interface RecommendedList extends Node {
670+
type: "recommended-list";
671+
heading?: string;
672+
children: Recommended[];
673+
}
659674
type TeaserConcept = {
660675
apiUrl: string;
661676
directType: string;
@@ -811,7 +826,7 @@ export declare namespace ContentTree {
811826
}
812827
}
813828
namespace loose {
814-
type BodyBlock = Paragraph | Heading | ImageSet | Flourish | BigNumber | CustomCodeComponent | Layout | List | Blockquote | Pullquote | ScrollyBlock | ThematicBreak | Table | Recommended | Tweet | Video | YoutubeVideo | Text;
829+
type BodyBlock = Paragraph | Heading | ImageSet | Flourish | BigNumber | CustomCodeComponent | Layout | List | Blockquote | Pullquote | ScrollyBlock | ThematicBreak | Table | Recommended | RecommendedList | Tweet | Video | YoutubeVideo | Text;
815830
type LayoutWidth = "auto" | "in-line" | "inset-left" | "inset-right" | "full-bleed" | "full-grid" | "mid-grid" | "full-width";
816831
type Phrasing = Text | Break | Strong | Emphasis | Strikethrough | Link;
817832
interface Node {
@@ -919,6 +934,11 @@ export declare namespace ContentTree {
919934
teaserTitleOverride?: string;
920935
teaser?: Teaser;
921936
}
937+
interface RecommendedList extends Node {
938+
type: "recommended-list";
939+
heading?: string;
940+
children: Recommended[];
941+
}
922942
type TeaserConcept = {
923943
apiUrl: string;
924944
directType: string;

schemas/body-tree.schema.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@
111111
{
112112
"$ref": "#/definitions/ContentTree.transit.Recommended"
113113
},
114+
{
115+
"$ref": "#/definitions/ContentTree.transit.RecommendedList"
116+
},
114117
{
115118
"$ref": "#/definitions/ContentTree.transit.Tweet"
116119
},
@@ -589,6 +592,30 @@
589592
],
590593
"type": "object"
591594
},
595+
"ContentTree.transit.RecommendedList": {
596+
"additionalProperties": false,
597+
"properties": {
598+
"children": {
599+
"items": {
600+
"$ref": "#/definitions/ContentTree.transit.Recommended"
601+
},
602+
"type": "array"
603+
},
604+
"data": {},
605+
"heading": {
606+
"type": "string"
607+
},
608+
"type": {
609+
"const": "recommended-list",
610+
"type": "string"
611+
}
612+
},
613+
"required": [
614+
"children",
615+
"type"
616+
],
617+
"type": "object"
618+
},
592619
"ContentTree.transit.ScrollyBlock": {
593620
"additionalProperties": false,
594621
"properties": {

schemas/content-tree.schema.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@
136136
{
137137
"$ref": "#/definitions/ContentTree.full.Recommended"
138138
},
139+
{
140+
"$ref": "#/definitions/ContentTree.full.RecommendedList"
141+
},
139142
{
140143
"$ref": "#/definitions/ContentTree.full.Tweet"
141144
},
@@ -1209,6 +1212,30 @@
12091212
],
12101213
"type": "object"
12111214
},
1215+
"ContentTree.full.RecommendedList": {
1216+
"additionalProperties": false,
1217+
"properties": {
1218+
"children": {
1219+
"items": {
1220+
"$ref": "#/definitions/ContentTree.full.Recommended"
1221+
},
1222+
"type": "array"
1223+
},
1224+
"data": {},
1225+
"heading": {
1226+
"type": "string"
1227+
},
1228+
"type": {
1229+
"const": "recommended-list",
1230+
"type": "string"
1231+
}
1232+
},
1233+
"required": [
1234+
"children",
1235+
"type"
1236+
],
1237+
"type": "object"
1238+
},
12121239
"ContentTree.full.ScrollyBlock": {
12131240
"additionalProperties": false,
12141241
"properties": {

schemas/transit-tree.schema.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@
136136
{
137137
"$ref": "#/definitions/ContentTree.transit.Recommended"
138138
},
139+
{
140+
"$ref": "#/definitions/ContentTree.transit.RecommendedList"
141+
},
139142
{
140143
"$ref": "#/definitions/ContentTree.transit.Tweet"
141144
},
@@ -614,6 +617,30 @@
614617
],
615618
"type": "object"
616619
},
620+
"ContentTree.transit.RecommendedList": {
621+
"additionalProperties": false,
622+
"properties": {
623+
"children": {
624+
"items": {
625+
"$ref": "#/definitions/ContentTree.transit.Recommended"
626+
},
627+
"type": "array"
628+
},
629+
"data": {},
630+
"heading": {
631+
"type": "string"
632+
},
633+
"type": {
634+
"const": "recommended-list",
635+
"type": "string"
636+
}
637+
},
638+
"required": [
639+
"children",
640+
"type"
641+
],
642+
"type": "object"
643+
},
617644
"ContentTree.transit.ScrollyBlock": {
618645
"additionalProperties": false,
619646
"properties": {

0 commit comments

Comments
 (0)