Skip to content

Add Puzzle Page: DCR layout for iframe-based puzzles (V0) - #16754

Open
andresilva-guardian wants to merge 24 commits into
mainfrom
afs/puzzle-page-design-v0
Open

andresilva-guardian wants to merge 24 commits into
mainfrom
afs/puzzle-page-design-v0

Conversation

@andresilva-guardian

@andresilva-guardian andresilva-guardian commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

What does this change?

Introduces Puzzle Page, a new generic DCR-owned page/layout for the Guardian's iframe-based puzzles (Sudoku easy/medium/hard/killer, Word wheel, Wordiply):

  • New POST /PuzzlePage endpoint, request validation (validate.puzzlePage.ts) and PuzzlePageLayout, a near-verbatim structural replica of CrosswordLayout (same ArticleTitle/ArticleHeadline/ArticleMeta/DiscussionLayout/StickyBottomBanner components and grid areas), with the crossword game body swapped for a sandboxed PuzzleIframe.island, which resolves per-provider (AmuseLabs/Wordiply) iframe URLs.
  • A print button (Sudoku only), via PrintButton.island.
  • A "More from Puzzles & games" related-puzzles rail on the puzzle page, styled identically to the Puzzles Hub's own card grid. Extracted the shared PuzzleCard/Rows implementation out of PuzzlesDirectory.tsx into a new, shared PuzzleCard.tsx, so the Hub and this rail render from the same code and can't visually drift apart. Cards collapse to a single column below the 740px breakpoint.
  • AB-test gating: the whole page sits behind the existing puzzles-new-hub experiment (mirroring the Puzzles Hub's own gate), with a separate v1-scoped flag gating the related rail specifically.
  • Ads: all ad slots are gated on canRenderAds, via a new isAdFreeUser field on FEPuzzlePageType, so ad-free subscribers don't see ads on puzzle pages either.
  • Comments are hardcoded off: Puzzle Page's current contract has no discussion/commentable concept.
  • Iframe sizing/responsiveness refinements (per-slug, per-device min-height configuration) and dateline-style puzzle date formatting.

Why?

Iframe-based puzzles didn't have a page template consistent with the rest of DCR. Crosswords already get this treatment via CrosswordLayout, but Sudoku/Word wheel/Wordiply were left without proper header/meta/print/ads/related-content handling. This brings them in line with the rest of the site, as part of the wider Puzzles & Games hub rollout.

Reusing the Hub's own card component for the related rail (rather than a second, independent styling of the same PuzzleItem data) keeps the two surfaces visually identical and avoids duplicated, divergence-prone CSS.

How has this change been tested?

  • Automated: unit/component tests added and updated for PuzzlePageLayout, PuzzleIframe, PuzzlesDirectory, validate.puzzlePage, the /PuzzlePage handler, and puzzleDate formatting.
  • Manual: run locally against the puzzle-page fixtures (fixtures/manual/puzzlePage.ts) across sudoku/word-wheel/wordiply, checking print button gating (Sudoku-only), ad gating (ad-free vs not), the puzzles-new-hub/v1 AB-test gates, and the related rail's card styling and responsive breakpoints (single column below 740px).

Screenshots

Before After
![before2][] Easy-sudoku-15-Jan-24-logic-puzzle-The-Guardian-09-18-2026_12_56_PM
![before2][] Easy-sudoku-15-Jan-24-logic-puzzle-The-Guardian-09-18-2026_12_56_PM (1)
![before2][] Easy-sudoku-15-Jan-24-logic-puzzle-The-Guardian-09-18-2026_12_56_PM (2)
![before2][] Easy-sudoku-15-Jan-24-logic-puzzle-The-Guardian-09-18-2026_12_57_PM

@andresilva-guardian andresilva-guardian added the feature Departmental tracking: work on a new feature label Sep 18, 2026
Restructure PuzzlePageLayout to use the same Article-domain components (ArticleTitle, ArticleHeadline, ArticleMeta, SubMeta, DiscussionLayout, StickyBottomBanner) and grid structure as CrosswordLayout, while keeping Puzzle-specific content. The puzzleGroup label is now rendered as a real section link through ArticleTitle instead of plain text. Update design format from Standard to Crossword to reuse existing width-handling logic. Add proper ad slot handling (header, survey, merchandising) and comments section (hardcoded off). Extensive comments document hardcoded fallback values for fields not present in FEPuzzlePageType.
Normalize puzzle headlines to match SEO titles (e.g., "Easy sudoku" not "sudoku-easy puzzle"). Add puzzle family names as series kickers using the existing tag pattern. Implement hardcoded Puzzles & Games sub-nav matching the crossword page's design. Change theme from News to Lifestyle to render proper palette colors. Suppress age warning for puzzle content. Export puzzlePageFormat for global style consistency.
- Introduced isAdFreeUser to FEPuzzlePageType to indicate if a reader has an ad-free subscription.
- Updated canRenderAds function to include FEPuzzlePageType.
- Modified PuzzlePageLayout to conditionally render ads based on isAdFreeUser.
- Enhanced validation tests to accommodate isAdFreeUser field.
@github-actions

github-actions Bot commented Sep 18, 2026

Copy link
Copy Markdown

🚀 Image pushed to AWS ECR

Image digest: sha256:d7f5d75aa0baa67d000e795a5595a61199d27fcc0d759d37b1886fdbef8183ad

🐛 Run the image locally

The following can be used to run the image locally:

# Refer to image using the immutable digest. Find alternatives below.
IMAGE_IDENTIFIER="@sha256:d7f5d75aa0baa67d000e795a5595a61199d27fcc0d759d37b1886fdbef8183ad"

# Refer to image using branch tag
# IMAGE_IDENTIFIER=":branch-afs-puzzle-page-design-v0"

# Refer to image using build tag
# IMAGE_IDENTIFIER=":build-31334"

# Set environment variables for the AWS CLI
AWS_PROFILE="<A_PROFILE_FROM_JANUS>"
AWS_DEFAULT_REGION="eu-west-1"

IMAGE_ACCOUNT_ID=$(aws ssm get-parameter --name /organisation/accounts/artifacts --query "Parameter.Value" --output text)
REGISTRY="${IMAGE_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com"
IMAGE="${REGISTRY}/guardian/dotcom-rendering${IMAGE_IDENTIFIER}"

# Login to AWS ECR https://docs.aws.amazon.com/AmazonECR/latest/userguide/registry_auth.html
aws ecr get-login-password | docker login --username AWS --password-stdin $REGISTRY

# Pull the image
docker pull $IMAGE

# Run the image. You'll likely need to set additional flags. See https://docs.docker.com/reference/cli/docker/container/run.
docker run $IMAGE

From guardian/actions-publish-image.

@andresilva-guardian andresilva-guardian changed the title Afs/puzzle page design v0 Add Puzzle Page: DCR layout for iframe-based puzzles (V0) Sep 18, 2026
@andresilva-guardian
andresilva-guardian marked this pull request as ready for review September 18, 2026 12:12
@andresilva-guardian
andresilva-guardian requested a review from a team as a code owner September 18, 2026 12:12
@github-actions

Copy link
Copy Markdown

Hello 👋! When you're ready to run Chromatic, please apply the run_chromatic label to this PR.

You will need to reapply the label each time you want to run Chromatic.

Click here to see the Chromatic project.

…ests

- Suppress declaration-no-important on the button's :focus outline
  override (existing, intentional !important; lint just needed the
  disable comment used elsewhere in the codebase).
- Update print button role/name assertions to match the actual
  "Print version" label (button text was changed but tests weren't).
- Drop the #dfp-ad--merchandising assertion from the non-ad-free ads
  test: that slot is gated behind showComments, which is permanently
  false on Puzzle Page, so it never renders regardless of ad-free
  status.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@andresilva-guardian andresilva-guardian added the run_chromatic Runs chromatic when label is applied label Sep 18, 2026
@github-actions github-actions Bot removed the run_chromatic Runs chromatic when label is applied label Sep 18, 2026

@gustavo-olmedo gustavo-olmedo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

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.

2 participants