diff --git a/src/components/LeftSidebar/LeftSidebar.astro b/src/components/LeftSidebar/LeftSidebar.astro
index c3e73a7c94935..edf6e18ec6b90 100644
--- a/src/components/LeftSidebar/LeftSidebar.astro
+++ b/src/components/LeftSidebar/LeftSidebar.astro
@@ -35,7 +35,7 @@ let activeTab: 'learn' | 'api' = 'learn';
// Certain pages are not in the sidebar nav, so we manually set the active tab based on other factors (e.g. Algolia page category).
const isReference = ['Error Reference', 'Reference'].includes(
- getPageCategory(new URL(currentPage, import.meta.url))
+ getPageCategory({ pathname: currentPage })
);
if (isReference) {
activeTab = 'api';
diff --git a/src/components/LeftSidebar/SidebarContent.astro b/src/components/LeftSidebar/SidebarContent.astro
index 6afd711d034ab..22eb038d2334b 100644
--- a/src/components/LeftSidebar/SidebarContent.astro
+++ b/src/components/LeftSidebar/SidebarContent.astro
@@ -1,5 +1,6 @@
---
-import { getLanguageFromURL, removeSubpageSegment } from '../../util';
+import { getLanguageFromURL } from '~/util';
+import { isSubPage } from '~/util/isSubPage';
export interface Props {
type: TabType;
@@ -44,11 +45,7 @@ const lang = getLanguageFromURL(Astro.url.pathname);
{isFallback && EN}
diff --git a/src/content/docs/es/core-concepts/sharing-state.mdx b/src/content/docs/es/core-concepts/sharing-state.mdx
index 8d56c02654dda..b8b00fa6f7fd2 100644
--- a/src/content/docs/es/core-concepts/sharing-state.mdx
+++ b/src/content/docs/es/core-concepts/sharing-state.mdx
@@ -1,6 +1,8 @@
---
title: Compartiendo Estado
+description: Learn how to share state across components — and frameworks! — with Nano Stores.
i18nReady: true
+type: recipe
---
import UIFrameworkTabs from '~/components/tabs/UIFrameworkTabs.astro'
diff --git a/src/content/docs/es/guides/rss.mdx b/src/content/docs/es/guides/rss.mdx
index 18566819280b7..22f2f3bc934d5 100644
--- a/src/content/docs/es/guides/rss.mdx
+++ b/src/content/docs/es/guides/rss.mdx
@@ -2,6 +2,7 @@
title: RSS
description: Introducción a RSS en Astro
i18nReady: true
+type: recipe
---
import PackageManagerTabs from '~/components/tabs/PackageManagerTabs.astro';
diff --git a/src/content/docs/fr/core-concepts/sharing-state.mdx b/src/content/docs/fr/core-concepts/sharing-state.mdx
index 33d33a24e3a88..cc293957de0b5 100644
--- a/src/content/docs/fr/core-concepts/sharing-state.mdx
+++ b/src/content/docs/fr/core-concepts/sharing-state.mdx
@@ -1,6 +1,8 @@
---
title: Partage d'État
+description: Learn how to share state across components — and frameworks! — with Nano Stores.
i18nReady: true
+type: recipe
---
import UIFrameworkTabs from '~/components/tabs/UIFrameworkTabs.astro'
import LoopingVideo from '~/components/LoopingVideo.astro'
diff --git a/src/content/docs/fr/guides/rss.mdx b/src/content/docs/fr/guides/rss.mdx
index 851447f047e8d..f2675796abf3c 100644
--- a/src/content/docs/fr/guides/rss.mdx
+++ b/src/content/docs/fr/guides/rss.mdx
@@ -1,6 +1,7 @@
---
title: Flux RSS
description: Une introduction aux flux RSS avec Astro.
+type: recipe
---
import PackageManagerTabs from '~/components/tabs/PackageManagerTabs.astro'
import Since from '~/components/Since.astro'
diff --git a/src/content/docs/ja/guides/rss.mdx b/src/content/docs/ja/guides/rss.mdx
index 6c30742fddaf2..1d2e707a0bbe8 100644
--- a/src/content/docs/ja/guides/rss.mdx
+++ b/src/content/docs/ja/guides/rss.mdx
@@ -2,6 +2,7 @@
title: RSS
description: AstroのRSS入門
i18nReady: true
+type: recipe
---
import PackageManagerTabs from '~/components/tabs/PackageManagerTabs.astro'
diff --git a/src/content/docs/pt-br/core-concepts/sharing-state.mdx b/src/content/docs/pt-br/core-concepts/sharing-state.mdx
index c6c22bb71ff17..e4a2497bfec32 100644
--- a/src/content/docs/pt-br/core-concepts/sharing-state.mdx
+++ b/src/content/docs/pt-br/core-concepts/sharing-state.mdx
@@ -1,6 +1,8 @@
---
title: Compartilhamento de Estado
+description: Aprenda como compartilhar estado entre componentes — e frameworks! — com Nano Stores.
i18nReady: true
+type: recipe
---
import UIFrameworkTabs from '~/components/tabs/UIFrameworkTabs.astro';
import LoopingVideo from '~/components/LoopingVideo.astro';
diff --git a/src/content/docs/pt-br/guides/rss.mdx b/src/content/docs/pt-br/guides/rss.mdx
index 34e5612d5f5bd..3feec642bce5a 100644
--- a/src/content/docs/pt-br/guides/rss.mdx
+++ b/src/content/docs/pt-br/guides/rss.mdx
@@ -2,6 +2,7 @@
title: RSS
description: Uma introdução a RSS em Astro
i18nReady: true
+type: recipe
---
import PackageManagerTabs from '~/components/tabs/PackageManagerTabs.astro';
import Since from '~/components/Since.astro';
diff --git a/src/content/docs/zh-cn/core-concepts/sharing-state.mdx b/src/content/docs/zh-cn/core-concepts/sharing-state.mdx
index cbdb1d9e99ca8..447a66ff9f457 100644
--- a/src/content/docs/zh-cn/core-concepts/sharing-state.mdx
+++ b/src/content/docs/zh-cn/core-concepts/sharing-state.mdx
@@ -1,6 +1,8 @@
---
title: 状态共享
+description: Learn how to share state across components — and frameworks! — with Nano Stores.
i18nReady: false
+type: recipe
---
import UIFrameworkTabs from '~/components/tabs/UIFrameworkTabs.astro'
import LoopingVideo from '~/components/LoopingVideo.astro'
diff --git a/src/content/docs/zh-cn/guides/rss.mdx b/src/content/docs/zh-cn/guides/rss.mdx
index bb968203569d8..82fa6c884bc62 100644
--- a/src/content/docs/zh-cn/guides/rss.mdx
+++ b/src/content/docs/zh-cn/guides/rss.mdx
@@ -1,6 +1,7 @@
---
title: RSS
description: Astro RSS 介绍
+type: recipe
---
Astro 支持为博客和其他内容网站快速自动生成 RSS 摘要。更多关于 RSS 摘要的信息参见 [aboutfeeds.com](https://aboutfeeds.com/)。
diff --git a/src/util.ts b/src/util.ts
index bf526d70fba2c..0b43ae52668ce 100644
--- a/src/util.ts
+++ b/src/util.ts
@@ -21,18 +21,3 @@ export const stripLangFromSlug = (slug: CollectionEntry<'docs'>['slug']) =>
/** Get a page’s lang tag from its slug (e.g. `'en/migrate'` => `'en'`). */
export const getLangFromSlug = (slug: CollectionEntry<'docs'>['slug']) => slug.split('/')[0];
-
-/** Remove the subpage segment of a URL string */
-export function removeSubpageSegment(path: string) {
- // Include new pages with subpages as part of this regex.
- const regex = /(?:install|deploy|integrations-guide|tutorial|migrate-to-astro|recipes|cms)\//;
- const matches = regex.exec(path);
-
- if (matches) {
- const matchIndex = matches.index;
- // Get the first slash index after the main page path segment.
- const slashIndex = path.slice(matchIndex).indexOf('/') + matchIndex;
- return path.slice(0, slashIndex);
- }
- return path;
-}
diff --git a/src/util/getPageCategory.ts b/src/util/getPageCategory.ts
index 17ded868b6d61..d7c5af7815b49 100644
--- a/src/util/getPageCategory.ts
+++ b/src/util/getPageCategory.ts
@@ -16,7 +16,7 @@ const categories = [
* @param url URL for the current page.
* @returns The category for the current page as used by Algolia DocSearch to group search results.
*/
-export function getPageCategory(url: URL) {
+export function getPageCategory(url: { pathname: string }) {
const langAgnosticPath = url.pathname.replace(/\/\w\w(-\w\w)?\//, '');
for (const [path, label] of categories) {
if (langAgnosticPath.startsWith(path)) return label;
diff --git a/src/util/isSubPage.ts b/src/util/isSubPage.ts
new file mode 100644
index 0000000000000..9de1b984f019c
--- /dev/null
+++ b/src/util/isSubPage.ts
@@ -0,0 +1,49 @@
+import type { CollectionEntry } from 'astro:content';
+import { englishPages } from '~/content';
+import { getPageCategory } from './getPageCategory';
+
+/** Remove the sub-page segment of a URL string */
+export function removeSubPageSegment(path: string) {
+ // Include new pages with sub-pages as part of this regex.
+ const regex = /(?:install|deploy|integrations-guide|tutorial|migrate-to-astro|recipes|cms)\//;
+ const matches = regex.exec(path);
+
+ if (matches) {
+ const matchIndex = matches.index;
+ // Get the first slash index after the main page path segment.
+ const slashIndex = path.slice(matchIndex).indexOf('/') + matchIndex;
+ return path.slice(0, slashIndex);
+ }
+ return path;
+}
+
+const typeIndexes: Partial['data']['type'], string>> = {
+ recipe: 'recipes',
+};
+
+const categoryIndex: Partial, string>> = {
+ 'Error Reference': 'reference/error-reference',
+};
+
+/**
+ * Test if `currentPage` is considered a sub-page of `parentSlug`.
+ * @param currentPage The full slug for the current page, e.g. `'en/guides/rss'`
+ * @param parentSlug The language-less slug for the parent to test against e.g. `'guides/content-collections'`
+ */
+export function isSubPage(currentPage: string, parentSlug: string): boolean {
+ // Test 1: do the two pages share a base URL segment?
+ if (removeSubPageSegment(currentPage).endsWith(removeSubPageSegment(parentSlug))) {
+ return true;
+ }
+ // Test 2: is there a known parent page for this page category?
+ const category = getPageCategory({ pathname: '/' + currentPage + '/' });
+ if (categoryIndex[category] === parentSlug) {
+ return true;
+ }
+ // Test 3: is there a known parent page for this page type?
+ const type = englishPages.find(({ slug }) => slug === currentPage)?.data.type;
+ if (type && typeIndexes[type] === parentSlug) {
+ return true;
+ }
+ return false;
+}