Skip to content

Conversation

@Georges-GNM
Copy link
Contributor

@Georges-GNM Georges-GNM commented Dec 15, 2025

What does this change?

Part of the AI tag pages work. This adds the content to the tag pages model, enabling it to be passed through from the work in this frontend PR, implements the figma designs (available here although there’s also been some subsequent decisions not updated in the figma), and includes new storybook stories for testing.

Worth flagging at the outset that this is all behind a 0% experiment in frontend - if not in the test, frontend doesn't retrieve the needed content (just returning None). In January, we plan to start a 50% test on a limited number of pages; after which we'll determine if we want to keep the feature and deploy it on a wider number of tags.

It looks like a big PR, but it's meant to comprehensively deliver the feature (with the associated model, data transformation and rendering changes, which has also meant splitting this up is arguably not ideal). A significant portion of the diff comes from code which is either very similar to an existing component, or from schema changes/fixtures/storybook setup.

Chromatic tests only flagged one false positive for an existing component (change of the classname), so I'm fairly confident this doesn't affect existing styling.




What does this actually change?

We add the content type to the tag page model, based on the structure provided by the tool and correspondingly sent by frontend.

As a quick overview, we have:
-> content
---> array of storylines
----> in each storyline, an array of categories (e.g. key stories, opinions, deep reads)
-----> in each category, an array of articles, with the minimum data required to render them by DCR (headline, url, publication date, maybe byline, image data and if relevant, main media data).

The content gets rendered in the tag page layout just below the first container (thereby always showing the most recent articles on a given tag at the top of the page). The designs are inspired by the front page redesign, and notably the flexible general container, so the implementation has taken this into account and tried to reuse existing logic where possible.

We add two new components, StorylineSection and StorylinesSection.importable. The former provides the general structure of the section (it's very similar to the FrontSection component, particularly in terms of the style and grid setup, but slightly adapted and removing unnecessary logic).

The latter calls an enhanceAITagPageContent function to transform the data sent by frontend, turning the very basic article information we receive (headline, url, image/multimedia data) into the DCRGroupedTrails and DCRFrontCard shape. Based on the categories these articles are a part of, we can be deterministic in terms of how values need to be defined for a DCRFrontCard (e.g. for the format). Most of these front cards end up being part of the standard group in a trail, but the key stories category is a bit different: the image for that gets taken from the first (latest) article in the category, and each of the headlines get used as the "supporting content" on the left of the image.

Once we've got the data in shape, each of the categories in a storyline gets rendered as a flexible general container. These are individual containers mainly so we can add the title of the category before them.

For the most part this just uses the pre-existing logic, but some variations needed to be tweaked (e.g. the rendering of the key stories category in particular), and so we pass a boolean storylinesStyle through FlexibleGeneral and Card to enable this (and add a SupportingKeyStoriesContent component, similar to the supporting content component, but with enough notable differences). CardAge and feature card components (FeatureCard and FeatureCardAge`) also get touched slightly, to ensure we display the age correctly (as the cards are displayed on an “archive” page, it feels important to indicate when the article was published).

The only piece of AI generated text, the titles of the storylines, get rendered at the top of the section. These are tabs that can be clicked on to switch stories, so we need this to be an island to enable the necessary javascript.

Few more points to note:

  • The storyline section has some text at the top left (under the "Storylines" container title), with a link that should point to further information - we've not settled on exactly where this is going yet, but I'd prefer to keep this text as is (and update the link in a subsequent PR) to keep a view of it as part of the design. In order to provide a valid link, I've pointed to the AI guidelines for now.
  • The bottom left of the storyline section (the standard "treats" position) makes use of the like/dislike feedback footer usually found in atoms. This is so we can try to get a bit more qualitative feedback from readers in the test. I've added the relevant component type to the thrift model and bumped the version of tracker.js to enable this (following this PR in Ophan)

Screenshots

Category Desktop Mobile
fullPage fullPage-desktop ![fullPage-mobile][]
keyStories keyStories-desktop ![keyStories-mobile][]
opinionsAndExplainers opinionsAndExplainers-desktop ![opinionsAndExplainers-mobile][]
deepReads deepReads-desktop ![deepReads-mobile][]
multimedia multimedia-desktop ![multimedia-mobile][]
profilesAndInterviews profilesAndInterviews-desktop ![profilesAndInterviews-mobile][]

[keyStories-mobile]:

[opinionsAndExplainers-mobile]:

[deepReads-mobile]:

[multimedia-mobile]:

[profilesAndInterviews-mobile]:

Desktop Mobile
before after

@Georges-GNM Georges-GNM added run_chromatic Runs chromatic when label is applied feature Departmental tracking: work on a new feature and removed run_chromatic Runs chromatic when label is applied labels Dec 15, 2025
@Georges-GNM Georges-GNM force-pushed the gl/sc-tag-page-mockup branch from 27791e1 to dd106f8 Compare December 15, 2025 11:10
@github-actions
Copy link

github-actions bot commented Dec 15, 2025

@github-actions github-actions bot removed the run_chromatic Runs chromatic when label is applied label Dec 15, 2025
@github-actions
Copy link

github-actions bot commented Dec 15, 2025

@Georges-GNM Georges-GNM force-pushed the gl/sc-tag-page-mockup branch from dd106f8 to d5fb9f0 Compare December 15, 2025 11:21
@Georges-GNM Georges-GNM added the run_chromatic Runs chromatic when label is applied label Dec 15, 2025
@github-actions github-actions bot removed the run_chromatic Runs chromatic when label is applied label Dec 15, 2025
@Georges-GNM Georges-GNM added the run_chromatic Runs chromatic when label is applied label Dec 15, 2025
@github-actions github-actions bot removed the run_chromatic Runs chromatic when label is applied label Dec 15, 2025
Copy link
Contributor

@fredex42 fredex42 left a comment

Choose a reason for hiding this comment

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

This looks great to me. I've noticed a few places where we could zap commented code and a couple of bits marked with eyes that might need another quick look but from a non-DCR expert point of view looking great 👍

Comment on lines 281 to 295
// const sectionHeadlineFromLeftCol = (borderColour: string) => css`
// ${from.leftCol} {
// position: relative;
// ::after {
// content: '';
// display: block;
// width: 1px;
// top: 0;
// height: 1.875rem;
// right: -10px;
// position: absolute;
// background-color: ${borderColour};
// }
// }
// `;
Copy link
Contributor

Choose a reason for hiding this comment

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

zappable?

dislikeHandler,
likeHandler,
}: Props) => {
const id = sectionId || 'unknown-id'; //todo: figure out what this should be
Copy link
Contributor

Choose a reason for hiding this comment

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

👀

Comment on lines 81 to 82
// ${textSans17};
// font-weight: 700;
Copy link
Contributor

Choose a reason for hiding this comment

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

Comment on lines 151 to 152
// console.log('StorylinesContent', StorylinesContent);
// const [storylines, SetStorylines] = useState<StorylinesContent>();
Copy link
Contributor

Choose a reason for hiding this comment

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

Comment on lines 155 to 173
// useEffect(() => {
// fetch(
// `http://localhost:9000/api/tag-page-rendering/${tagPage.pageId}`,
// {
// headers: {
// 'Content-Type': 'application/json',
// },
// credentials: 'include',
// },
// )
// .then((response) => {
// console.log('response', response);
// return response.json();
// })
// .then((data) => SetStorylines(data))
// .catch((error) => {
// console.error('Error fetching storylines data:', error);
// });
// }, []);
Copy link
Contributor

Choose a reason for hiding this comment

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

image={tagPage.header.image}
/>
{tagPage.groupedTrails.map((groupedTrails, index) => {
// console.log("groupedTrails in TagPageLayout:", groupedTrails);
Copy link
Contributor

Choose a reason for hiding this comment

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


const insertSCSection =
tagPage.storylinesContent &&
// isSCTagPage &&
Copy link
Contributor

Choose a reason for hiding this comment

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

article.image?.isAvatar
? article.image?.src
: undefined, // will need to be set for opinion pieces
// mainMedia: undefined, // ought to be set for multimedia pieces, but missing the extra info like count?
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this a TBD?

Comment on lines 96 to 98
// const articleAge =
// article.publicationTime &&
// timeAgo(new Date(article.publicationTime).getTime()).toString();
Copy link
Contributor

Choose a reason for hiding this comment

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

categories: ParsedCategory[];
};

// probably want to add a generic category type mapping to those in supercharger (e.g. opinions) and map this to a container type and title (e.g. "Contrasting Opinions" + "flexible/general")
Copy link
Contributor

Choose a reason for hiding this comment

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

💯

<>
<StorylineSection
title="Storylines"
containerPalette="LongRunningAltPalette"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Feels a bit hacky to hard code this, but this provides some styling (notably the greyed background) without having to add more palette variations and still sticking to the “container overrides” pattern in a section.

@Georges-GNM Georges-GNM force-pushed the gl/sc-tag-page-mockup branch from 155c448 to 3c40535 Compare December 23, 2025 15:06
@Georges-GNM Georges-GNM changed the title tag page wip Add Storylines content to tag pages Dec 29, 2025
@Georges-GNM Georges-GNM added the run_chromatic Runs chromatic when label is applied label Dec 29, 2025
@github-actions github-actions bot removed the run_chromatic Runs chromatic when label is applied label Dec 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Departmental tracking: work on a new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants