From d5898e01a78506bffcc3b45074ebad2d6e3ac7fb Mon Sep 17 00:00:00 2001
From: "arrz.dev" <55147716+arrzdev@users.noreply.github.com>
Date: Mon, 2 Nov 2026 07:02:05 +0000
Subject: [PATCH] feat(game): link each guide to the other three at the end of
the page
A Related guides block closes /rules, /strategy, /opening-moves and
/starting-positions. Labels reuse each page's heading; the block heading
is one new key in every locale. Plain links in the server HTML, under the
page's language prefix, below the play block.
---
.../src/components/manual/related-guides.tsx | 52 ++++++++++++
apps/game/src/i18n/locales/de/game.json | 3 +-
apps/game/src/i18n/locales/en/game.json | 3 +-
apps/game/src/i18n/locales/es/game.json | 3 +-
apps/game/src/i18n/locales/fr/game.json | 3 +-
apps/game/src/i18n/locales/hi/game.json | 3 +-
apps/game/src/i18n/locales/it/game.json | 3 +-
apps/game/src/i18n/locales/ja/game.json | 3 +-
apps/game/src/i18n/locales/ko/game.json | 3 +-
apps/game/src/i18n/locales/nl/game.json | 3 +-
apps/game/src/i18n/locales/pl/game.json | 3 +-
apps/game/src/i18n/locales/pt/game.json | 3 +-
apps/game/src/i18n/locales/tr/game.json | 3 +-
apps/game/src/i18n/locales/zh/game.json | 3 +-
.../src/routing/pages/opening-moves.page.tsx | 3 +
apps/game/src/routing/pages/rules.page.tsx | 3 +
.../routing/pages/starting-positions.page.tsx | 3 +
apps/game/src/routing/pages/strategy.page.tsx | 3 +
apps/game/src/routing/seo-pages.test.ts | 8 +-
apps/game/src/routing/seo-pages.ts | 8 +-
e2e/related-guides.spec.ts | 85 +++++++++++++++++++
e2e/seo.spec.ts | 8 +-
e2e/strategy-page.spec.ts | 2 +
23 files changed, 189 insertions(+), 25 deletions(-)
create mode 100644 apps/game/src/components/manual/related-guides.tsx
create mode 100644 e2e/related-guides.spec.ts
diff --git a/apps/game/src/components/manual/related-guides.tsx b/apps/game/src/components/manual/related-guides.tsx
new file mode 100644
index 00000000..0d935a8a
--- /dev/null
+++ b/apps/game/src/components/manual/related-guides.tsx
@@ -0,0 +1,52 @@
+import { Link } from "@tanstack/react-router"
+import { useTranslation } from "react-i18next"
+
+/** The guides, in reading order, each named by its page's own heading. */
+const GUIDES = [
+ ["/rules", "game:rules.heading"],
+ ["/strategy", "game:strategy.heading"],
+ ["/opening-moves", "game:openings.heading"],
+ ["/starting-positions", "game:positions.heading"],
+] as const
+
+export type GuidePath = (typeof GUIDES)[number][0]
+
+/**
+ * The other guides, at the end of a guide: a reader who finished one finds the
+ * next, and a crawler finds every guide from each of them. Plain links, which
+ * the router gives the page's language prefix (/de/strategy). After the last
+ * chapter and outside it, so the way to the board above stays where it was.
+ */
+export function RelatedGuides({ current }: { current: GuidePath }) {
+ const { t } = useTranslation()
+
+ return (
+
+ )
+}
diff --git a/apps/game/src/i18n/locales/de/game.json b/apps/game/src/i18n/locales/de/game.json
index 5cd66c40..daa0b0ca 100644
--- a/apps/game/src/i18n/locales/de/game.json
+++ b/apps/game/src/i18n/locales/de/game.json
@@ -332,5 +332,6 @@
"next": "Weiter",
"done": "Verstanden",
"skip": "Überspringen"
- }
+ },
+ "related_guides": "Weitere Anleitungen"
}
diff --git a/apps/game/src/i18n/locales/en/game.json b/apps/game/src/i18n/locales/en/game.json
index 158ae144..e5577aec 100644
--- a/apps/game/src/i18n/locales/en/game.json
+++ b/apps/game/src/i18n/locales/en/game.json
@@ -515,5 +515,6 @@
"next": "Next",
"done": "Got it",
"skip": "Skip"
- }
+ },
+ "related_guides": "Related guides"
}
diff --git a/apps/game/src/i18n/locales/es/game.json b/apps/game/src/i18n/locales/es/game.json
index 761a6bc1..aaa6d9fa 100644
--- a/apps/game/src/i18n/locales/es/game.json
+++ b/apps/game/src/i18n/locales/es/game.json
@@ -332,5 +332,6 @@
"next": "Siguiente",
"done": "Entendido",
"skip": "Omitir"
- }
+ },
+ "related_guides": "Guías relacionadas"
}
diff --git a/apps/game/src/i18n/locales/fr/game.json b/apps/game/src/i18n/locales/fr/game.json
index 71ff6fd1..64855d64 100644
--- a/apps/game/src/i18n/locales/fr/game.json
+++ b/apps/game/src/i18n/locales/fr/game.json
@@ -332,5 +332,6 @@
"next": "Suivant",
"done": "Compris",
"skip": "Passer"
- }
+ },
+ "related_guides": "Guides associés"
}
diff --git a/apps/game/src/i18n/locales/hi/game.json b/apps/game/src/i18n/locales/hi/game.json
index 34824396..3f250e44 100644
--- a/apps/game/src/i18n/locales/hi/game.json
+++ b/apps/game/src/i18n/locales/hi/game.json
@@ -332,5 +332,6 @@
"next": "आगे",
"done": "समझ गया",
"skip": "छोड़ें"
- }
+ },
+ "related_guides": "संबंधित गाइड"
}
diff --git a/apps/game/src/i18n/locales/it/game.json b/apps/game/src/i18n/locales/it/game.json
index 2ec00e1d..c4124ad5 100644
--- a/apps/game/src/i18n/locales/it/game.json
+++ b/apps/game/src/i18n/locales/it/game.json
@@ -332,5 +332,6 @@
"next": "Avanti",
"done": "Ho capito",
"skip": "Salta"
- }
+ },
+ "related_guides": "Guide correlate"
}
diff --git a/apps/game/src/i18n/locales/ja/game.json b/apps/game/src/i18n/locales/ja/game.json
index 4633c3d8..0da24ae3 100644
--- a/apps/game/src/i18n/locales/ja/game.json
+++ b/apps/game/src/i18n/locales/ja/game.json
@@ -331,5 +331,6 @@
"next": "次へ",
"done": "わかった",
"skip": "スキップ"
- }
+ },
+ "related_guides": "関連ガイド"
}
diff --git a/apps/game/src/i18n/locales/ko/game.json b/apps/game/src/i18n/locales/ko/game.json
index 8cb4326c..c9ce1ab4 100644
--- a/apps/game/src/i18n/locales/ko/game.json
+++ b/apps/game/src/i18n/locales/ko/game.json
@@ -331,5 +331,6 @@
"next": "다음",
"done": "알겠어요",
"skip": "건너뛰기"
- }
+ },
+ "related_guides": "관련 가이드"
}
diff --git a/apps/game/src/i18n/locales/nl/game.json b/apps/game/src/i18n/locales/nl/game.json
index 89614840..e6ff5395 100644
--- a/apps/game/src/i18n/locales/nl/game.json
+++ b/apps/game/src/i18n/locales/nl/game.json
@@ -332,5 +332,6 @@
"next": "Volgende",
"done": "Begrepen",
"skip": "Overslaan"
- }
+ },
+ "related_guides": "Gerelateerde gidsen"
}
diff --git a/apps/game/src/i18n/locales/pl/game.json b/apps/game/src/i18n/locales/pl/game.json
index 7845a006..62a7f5c2 100644
--- a/apps/game/src/i18n/locales/pl/game.json
+++ b/apps/game/src/i18n/locales/pl/game.json
@@ -333,5 +333,6 @@
"next": "Dalej",
"done": "Rozumiem",
"skip": "Pomiń"
- }
+ },
+ "related_guides": "Powiązane poradniki"
}
diff --git a/apps/game/src/i18n/locales/pt/game.json b/apps/game/src/i18n/locales/pt/game.json
index 8c4bc977..45996b47 100644
--- a/apps/game/src/i18n/locales/pt/game.json
+++ b/apps/game/src/i18n/locales/pt/game.json
@@ -332,5 +332,6 @@
"next": "Seguinte",
"done": "Percebi",
"skip": "Saltar"
- }
+ },
+ "related_guides": "Guias relacionados"
}
diff --git a/apps/game/src/i18n/locales/tr/game.json b/apps/game/src/i18n/locales/tr/game.json
index acaff69c..87ed20fc 100644
--- a/apps/game/src/i18n/locales/tr/game.json
+++ b/apps/game/src/i18n/locales/tr/game.json
@@ -331,5 +331,6 @@
"next": "İleri",
"done": "Anladım",
"skip": "Geç"
- }
+ },
+ "related_guides": "İlgili rehberler"
}
diff --git a/apps/game/src/i18n/locales/zh/game.json b/apps/game/src/i18n/locales/zh/game.json
index 9c0e24d0..86ed3405 100644
--- a/apps/game/src/i18n/locales/zh/game.json
+++ b/apps/game/src/i18n/locales/zh/game.json
@@ -331,5 +331,6 @@
"next": "下一步",
"done": "知道了",
"skip": "跳过"
- }
+ },
+ "related_guides": "相关指南"
}
diff --git a/apps/game/src/routing/pages/opening-moves.page.tsx b/apps/game/src/routing/pages/opening-moves.page.tsx
index e35958e4..bc29d6c4 100644
--- a/apps/game/src/routing/pages/opening-moves.page.tsx
+++ b/apps/game/src/routing/pages/opening-moves.page.tsx
@@ -3,6 +3,7 @@ import { Trans, useTranslation } from "react-i18next"
import type { ManualChapter } from "@/components/manual/chapter"
import { Chapter } from "@/components/manual/chapter"
import { ManualHero, ManualPage } from "@/components/manual/manual-page"
+import { RelatedGuides } from "@/components/manual/related-guides"
import { PlayBlock } from "@/components/play-block"
import { SubpageHeader } from "@/components/ui/subpage-header"
import { COMPUTER_GAME } from "@/hooks/use-play-actions"
@@ -118,6 +119,8 @@ function OpeningMovesPage() {