https://docs.rdlabo.dev/projects/capacitor-admob/docs/rewarded
diff --git a/projects/docs/src/app/docs/docs-data.ts b/projects/docs/src/app/docs/docs-data.ts
index 8595e1d..3aa01ea 100644
--- a/projects/docs/src/app/docs/docs-data.ts
+++ b/projects/docs/src/app/docs/docs-data.ts
@@ -63,6 +63,7 @@ export interface DocsPageSummary {
title: string;
navTitle: string;
seoTitle?: string;
+ seoDescription?: string;
updatedAt?: string;
slug: string;
section: string;
diff --git a/projects/docs/src/app/docs/docs-page.ts b/projects/docs/src/app/docs/docs-page.ts
index 25a34da..919662d 100644
--- a/projects/docs/src/app/docs/docs-page.ts
+++ b/projects/docs/src/app/docs/docs-page.ts
@@ -231,7 +231,7 @@ export class DocsPageComponent implements OnInit, AfterViewInit {
this.#seo.setPage({
title:
page.seoTitle ?? `${page.title} - ${project.shortName} - rdlabo.dev`,
- description: `${page.title}. ${project.description}`,
+ description: page.seoDescription ?? `${page.title}. ${project.description}`,
path: page.path,
structuredData: docsBreadcrumbStructuredData(this.#locale, [
{ name: 'rdlabo.dev', path: '/' },
diff --git a/projects/docs/src/app/docs/landing-page.spec.ts b/projects/docs/src/app/docs/landing-page.spec.ts
index debbc8f..ccbf0a7 100644
--- a/projects/docs/src/app/docs/landing-page.spec.ts
+++ b/projects/docs/src/app/docs/landing-page.spec.ts
@@ -27,7 +27,9 @@ describe('LandingPageComponent', () => {
it('renders a manifest-driven Stripe landing page', async () => {
const compiled = await setup('stripe');
- expect(TestBed.inject(Title).getTitle()).toBe('Stripe - rdlabo.dev');
+ expect(TestBed.inject(Title).getTitle()).toBe(
+ 'Capacitor Stripe Plugin Documentation | rdlabo',
+ );
expect(compiled.querySelector('h1')?.textContent).toContain(
'Accept Stripe payments in Capacitor apps',
);
diff --git a/projects/docs/src/app/generated/project-catalog.generated.ts b/projects/docs/src/app/generated/project-catalog.generated.ts
index ad00a3d..85ca629 100644
--- a/projects/docs/src/app/generated/project-catalog.generated.ts
+++ b/projects/docs/src/app/generated/project-catalog.generated.ts
@@ -390,8 +390,6 @@ export const PROJECTS_EN = [
{
"title": "Getting Started",
"navTitle": "Getting Started",
- "seoTitle": "Angular CDK Variable Height Virtual Scroll Setup | rdlabo",
- "updatedAt": "2026-08-25",
"slug": "readme",
"section": "Quickstart",
"path": "/projects/ngx-cdk-scroll-strategies/docs/readme"
@@ -399,8 +397,6 @@ export const PROJECTS_EN = [
{
"title": "Simple Usage",
"navTitle": "Simple Usage",
- "seoTitle": "Angular CDK Virtual Scroll: Variable Height Example | rdlabo",
- "updatedAt": "2026-08-25",
"demo": {
"url": "https://rdlabo-ionic-angular-library.netlify.app/main/scroll-strategies/simple",
"title": "Interactive simple virtual scroll demo"
@@ -412,8 +408,6 @@ export const PROJECTS_EN = [
{
"title": "Advanced Usage",
"navTitle": "Advanced Usage",
- "seoTitle": "Angular CDK Virtual Scroll: Dynamic Item Height | rdlabo",
- "updatedAt": "2026-08-25",
"demo": {
"url": "https://rdlabo-ionic-angular-library.netlify.app/main/scroll-strategies/advanced",
"title": "Interactive advanced virtual scroll demo"
@@ -425,8 +419,6 @@ export const PROJECTS_EN = [
{
"title": "Reverse Scroll",
"navTitle": "Reverse Scroll",
- "seoTitle": "Angular CDK Reverse Virtual Scroll for Chat UIs | rdlabo",
- "updatedAt": "2026-08-25",
"demo": {
"url": "https://rdlabo-ionic-angular-library.netlify.app/main/scroll-strategies/reverse",
"title": "Interactive reverse virtual scroll demo"
@@ -438,8 +430,6 @@ export const PROJECTS_EN = [
{
"title": "FAQ",
"navTitle": "FAQ",
- "seoTitle": "Angular CDK Virtual Scroll: Autosize vs Variable Height",
- "updatedAt": "2026-08-25",
"slug": "faq",
"section": "Guides",
"path": "/projects/ngx-cdk-scroll-strategies/docs/faq"
@@ -1034,7 +1024,8 @@ export const PROJECTS_EN = [
"category": "capacitor-plugins",
"icon": "payments",
"version": "8.2.1",
- "description": "Native Stripe payments for Capacitor applications.",
+ "seoTitle": "Capacitor Stripe Plugin Documentation | rdlabo",
+ "description": "Integrate Stripe PaymentSheet, Apple Pay, and Google Pay in Capacitor apps with @capacitor-community/stripe for iOS, Android, and web.",
"headline": "Accept Stripe payments in Capacitor apps",
"overview": "Present native PaymentSheet and PaymentFlow, accept Apple Pay and Google Pay, and integrate payments on the web from the same Capacitor codebase.",
"featuresHeading": "What you can build",
@@ -1114,7 +1105,6 @@ export const PROJECTS_EN = [
{
"title": "PaymentSheet",
"navTitle": "PaymentSheet",
- "seoTitle": "Capacitor Stripe PaymentSheet API | rdlabo",
"slug": "payment-sheet",
"section": "Methods",
"path": "/projects/capacitor-stripe/docs/payment-sheet"
@@ -2037,8 +2027,6 @@ export const PROJECTS_JA = [
{
"title": "はじめに",
"navTitle": "はじめに",
- "seoTitle": "Angular CDK可変高さVirtual Scrollの導入方法 | rdlabo",
- "updatedAt": "2026-08-25",
"slug": "readme",
"section": "クイックスタート",
"path": "/projects/ngx-cdk-scroll-strategies/docs/readme"
@@ -2046,8 +2034,6 @@ export const PROJECTS_JA = [
{
"title": "シンプルな使い方",
"navTitle": "シンプルな使い方",
- "seoTitle": "Angular CDK Virtual Scrollの可変高さサンプル | rdlabo",
- "updatedAt": "2026-08-25",
"demo": {
"url": "https://rdlabo-ionic-angular-library.netlify.app/main/scroll-strategies/simple",
"title": "Simple Virtual Scrollの操作デモ"
@@ -2059,8 +2045,6 @@ export const PROJECTS_JA = [
{
"title": "応用的な使い方",
"navTitle": "応用的な使い方",
- "seoTitle": "Angular CDK Virtual Scrollで動的なItem Heightを計測 | rdlabo",
- "updatedAt": "2026-08-25",
"demo": {
"url": "https://rdlabo-ionic-angular-library.netlify.app/main/scroll-strategies/advanced",
"title": "Advanced Virtual Scrollの操作デモ"
@@ -2072,8 +2056,6 @@ export const PROJECTS_JA = [
{
"title": "リバーススクロール",
"navTitle": "リバーススクロール",
- "seoTitle": "Angular CDK Reverse Virtual ScrollでChat UIを実装 | rdlabo",
- "updatedAt": "2026-08-25",
"demo": {
"url": "https://rdlabo-ionic-angular-library.netlify.app/main/scroll-strategies/reverse",
"title": "Reverse Virtual Scrollの操作デモ"
@@ -2085,8 +2067,6 @@ export const PROJECTS_JA = [
{
"title": "FAQ",
"navTitle": "FAQ",
- "seoTitle": "Angular CDK Virtual Scrollのautosizeと可変高さの違い",
- "updatedAt": "2026-08-25",
"slug": "faq",
"section": "ガイド",
"path": "/projects/ngx-cdk-scroll-strategies/docs/faq"
@@ -2681,7 +2661,8 @@ export const PROJECTS_JA = [
"category": "capacitor-plugins",
"icon": "payments",
"version": "8.2.1",
- "description": "Capacitor アプリで Stripe のネイティブ決済を利用するためのプラグイン。",
+ "seoTitle": "Capacitor Stripe プラグイン ドキュメント | rdlabo",
+ "description": "Capacitorアプリに@capacitor-community/stripeを導入し、iOS・Android・WebでPaymentSheet、Apple Pay、Google Payを実装するためのドキュメント。",
"headline": "CapacitorアプリでStripe決済を受け付ける",
"overview": "同じCapacitorコードベースからネイティブのPaymentSheetとPaymentFlow、Apple Pay、Google Pay、Web決済を利用できます。",
"featuresHeading": "実装できること",
@@ -2761,7 +2742,6 @@ export const PROJECTS_JA = [
{
"title": "PaymentSheet",
"navTitle": "PaymentSheet",
- "seoTitle": "Capacitor Stripe PaymentSheet API リファレンス | rdlabo",
"slug": "payment-sheet",
"section": "メソッド",
"path": "/projects/capacitor-stripe/docs/payment-sheet"
diff --git a/projects/docs/src/app/generated/projects/admob.en.generated.ts b/projects/docs/src/app/generated/projects/admob.en.generated.ts
index b34526a..cec042c 100644
--- a/projects/docs/src/app/generated/projects/admob.en.generated.ts
+++ b/projects/docs/src/app/generated/projects/admob.en.generated.ts
@@ -37,6 +37,9 @@ export const PROJECT = {
{
"title": "Getting Started",
"navTitle": "Getting Started",
+ "seoTitle": "Capacitor AdMob Plugin Setup Guide | rdlabo",
+ "seoDescription": "Install and configure @capacitor-community/admob to initialize Google Mobile Ads and display native ads in Capacitor apps on iOS and Android.",
+ "updatedAt": "2026-08-31",
"slug": "readme",
"file": "readme.md",
"section": "Quickstart",
@@ -177,6 +180,9 @@ export const PROJECT = {
{
"title": "Interstitial Ads",
"navTitle": "Interstitial Ads",
+ "seoTitle": "Capacitor AdMob Interstitial Ads Guide | rdlabo",
+ "seoDescription": "Prepare, show, and handle interstitial ad events in Capacitor apps with @capacitor-community/admob on iOS and Android.",
+ "updatedAt": "2026-08-31",
"slug": "interstitial",
"file": "interstitial.md",
"section": "Ad formats",
diff --git a/projects/docs/src/app/generated/projects/admob.ja.generated.ts b/projects/docs/src/app/generated/projects/admob.ja.generated.ts
index 628733b..de97421 100644
--- a/projects/docs/src/app/generated/projects/admob.ja.generated.ts
+++ b/projects/docs/src/app/generated/projects/admob.ja.generated.ts
@@ -37,6 +37,9 @@ export const PROJECT = {
{
"title": "はじめに",
"navTitle": "はじめに",
+ "seoTitle": "Capacitor AdMob プラグイン導入ガイド | rdlabo",
+ "seoDescription": "@capacitor-community/admobを導入し、iOS・AndroidのCapacitorアプリでGoogle Mobile Adsを初期化してネイティブ広告を表示します。",
+ "updatedAt": "2026-08-31",
"slug": "readme",
"file": "readme.md",
"section": "クイックスタート",
@@ -273,6 +276,9 @@ export const PROJECT = {
{
"title": "インタースティシャル広告",
"navTitle": "インタースティシャル広告",
+ "seoTitle": "Capacitor AdMobインタースティシャル広告ガイド | rdlabo",
+ "seoDescription": "@capacitor-community/admobを使い、iOS・AndroidのCapacitorアプリでインタースティシャル広告の準備・表示・Event処理を実装します。",
+ "updatedAt": "2026-08-31",
"slug": "interstitial",
"file": "interstitial.md",
"section": "広告フォーマット",
diff --git a/projects/docs/src/app/generated/projects/eslint-plugin-rules.en.generated.ts b/projects/docs/src/app/generated/projects/eslint-plugin-rules.en.generated.ts
index 90de746..c820f6c 100644
--- a/projects/docs/src/app/generated/projects/eslint-plugin-rules.en.generated.ts
+++ b/projects/docs/src/app/generated/projects/eslint-plugin-rules.en.generated.ts
@@ -70,6 +70,9 @@ export const PROJECT = {
{
"title": "Configuration",
"navTitle": "Configuration",
+ "seoTitle": "Configure Angular and Ionic ESLint Rules | rdlabo",
+ "seoDescription": "Configure @rdlabo/eslint-plugin-rules with flat config presets for Angular, Ionic, or framework-independent TypeScript projects.",
+ "updatedAt": "2026-08-31",
"slug": "configuration",
"file": "configuration.md",
"section": "Guide",
@@ -138,6 +141,9 @@ export const PROJECT = {
{
"title": "Rules",
"navTitle": "Rules",
+ "seoTitle": "Angular, Ionic, and TypeScript ESLint Rules | rdlabo",
+ "seoDescription": "Browse every @rdlabo/eslint-plugin-rules rule for Angular Signals, Ionic components, component boundaries, forms, and safe asynchronous code.",
+ "updatedAt": "2026-08-31",
"slug": "rules",
"file": "rules.md",
"section": "Reference",
diff --git a/projects/docs/src/app/generated/projects/eslint-plugin-rules.ja.generated.ts b/projects/docs/src/app/generated/projects/eslint-plugin-rules.ja.generated.ts
index bb65adb..a31fe2f 100644
--- a/projects/docs/src/app/generated/projects/eslint-plugin-rules.ja.generated.ts
+++ b/projects/docs/src/app/generated/projects/eslint-plugin-rules.ja.generated.ts
@@ -60,6 +60,9 @@ export const PROJECT = {
{
"title": "設定",
"navTitle": "設定",
+ "seoTitle": "Angular・Ionic向けESLintルールの設定 | rdlabo",
+ "seoDescription": "@rdlabo/eslint-plugin-rulesのFlat Configを使い、Angular・Ionic・汎用TypeScript向けのESLintプリセットを設定します。",
+ "updatedAt": "2026-08-31",
"slug": "configuration",
"file": "configuration.md",
"section": "ガイド",
@@ -128,6 +131,9 @@ export const PROJECT = {
{
"title": "ルール一覧",
"navTitle": "ルール一覧",
+ "seoTitle": "Angular・Ionic・TypeScript向けESLintルール一覧 | rdlabo",
+ "seoDescription": "Angular Signal、Ionic Component、Component境界、フォーム、安全な非同期処理を検査する@rdlabo/eslint-plugin-rulesのルール一覧です。",
+ "updatedAt": "2026-08-31",
"slug": "rules",
"file": "rules.md",
"section": "リファレンス",
diff --git a/projects/docs/src/app/generated/projects/ionic-angular-scroll-header.en.generated.ts b/projects/docs/src/app/generated/projects/ionic-angular-scroll-header.en.generated.ts
index daaaa83..3bda22b 100644
--- a/projects/docs/src/app/generated/projects/ionic-angular-scroll-header.en.generated.ts
+++ b/projects/docs/src/app/generated/projects/ionic-angular-scroll-header.en.generated.ts
@@ -117,6 +117,9 @@ export const PROJECT = {
{
"title": "Safe Area",
"navTitle": "Safe Area",
+ "seoTitle": "Ionic Safe Area with Scroll-Aware Headers | rdlabo",
+ "seoDescription": "Configure hidden safe-area headers and always-visible native headers with @rdlabo/ionic-angular-scroll-header for Ionic content layouts.",
+ "updatedAt": "2026-08-31",
"slug": "safe-area",
"file": "safe-area.md",
"section": "Guides",
diff --git a/projects/docs/src/app/generated/projects/ionic-angular-scroll-header.ja.generated.ts b/projects/docs/src/app/generated/projects/ionic-angular-scroll-header.ja.generated.ts
index b2adcb1..8295887 100644
--- a/projects/docs/src/app/generated/projects/ionic-angular-scroll-header.ja.generated.ts
+++ b/projects/docs/src/app/generated/projects/ionic-angular-scroll-header.ja.generated.ts
@@ -85,7 +85,7 @@ export const PROJECT = {
"file": "ion-content.md",
"section": "ガイド",
"path": "/projects/ionic-angular-scroll-header/docs/ion-content",
- "html": "Ionic Content に Scroll 連動 Header を付けます。インストール のあとで呼び出します。
\n\nimport { ScrollHeaderDirective } from '@rdlabo/ionic-angular-scroll-header';\n@Component({\n ...\n imports: [\n ScrollHeaderDirective\n ],\n})\n
<ion-header class=\"hidden\"><ion-toolbar></ion-toolbar></ion-header>\n<!-- set hidden header for safe-area -->\n<ion-content rdlaboScrollHeader>\n <ion-header>\n <ion-toolbar>...</ion-toolbar>\n <!-- Default Header for display -->\n </ion-header>\n ...Your Content\n</ion-content>\n
",
+ "html": "Ionic Content に Scroll 連動 Header を付けます。インストール のあとで呼び出します。Safe Area用の非表示Headerと常時表示するNative Headerの使い分けは、Safe Areaガイドを参照してください。
\n\nimport { ScrollHeaderDirective } from '@rdlabo/ionic-angular-scroll-header';\n@Component({\n ...\n imports: [\n ScrollHeaderDirective\n ],\n})\n
<ion-header class=\"hidden\"><ion-toolbar></ion-toolbar></ion-header>\n<!-- set hidden header for safe-area -->\n<ion-content rdlaboScrollHeader>\n <ion-header>\n <ion-toolbar>...</ion-toolbar>\n <!-- Default Header for display -->\n </ion-header>\n ...Your Content\n</ion-content>\n
",
"headings": [],
"codes": [],
"scrollMap": [],
@@ -117,11 +117,14 @@ export const PROJECT = {
{
"title": "Safe Area",
"navTitle": "Safe Area",
+ "seoTitle": "IonicのSafe AreaとScroll連動Header | rdlabo",
+ "seoDescription": "Ionic・Angular CDKのScroll連動Headerで、Safe Area用の非表示Headerと常時表示するNative Headerを設定する方法を解説します。",
+ "updatedAt": "2026-08-31",
"slug": "safe-area",
"file": "safe-area.md",
"section": "ガイド",
"path": "/projects/ionic-angular-scroll-header/docs/safe-area",
- "html": "Safe Area 用の非表示 Header と常時表示 Native Header です。
\n\nもちろん、次のように ion-content にセーフエリアを設定することもできます。
\nion-content {\n padding-top: var(--ion-safe-area-top, 0);\n}\n
ただし、セーフエリアのために ion-header と ion-toolbar を明示的に置く方が望ましいと考えました。
\n\n可能です。クラス名に native-header を追加すると、2 つの Header をよりスムーズに扱えます。
\n- <ion-header class=\"hidden\"><ion-toolbar></ion-toolbar></ion-header>\n+ <ion-header class=\"native-header\">\n+ <ion-toolbar><ion-title>Native Header</ion-title></ion-toolbar>\n+ </ion-header>\n
",
+ "html": "Safe Area 用の非表示 Header と常時表示 Native Header です。
\nまずIonContentガイドのScroll連動Headerを設定し、このページのHeader構成を用途に応じて選択してください。
\n\nもちろん、次のように ion-content にセーフエリアを設定することもできます。
\nion-content {\n padding-top: var(--ion-safe-area-top, 0);\n}\n
ただし、セーフエリアのために ion-header と ion-toolbar を明示的に置く方が望ましいと考えました。
\n\n可能です。クラス名に native-header を追加すると、2 つの Header をよりスムーズに扱えます。
\n- <ion-header class=\"hidden\"><ion-toolbar></ion-toolbar></ion-header>\n+ <ion-header class=\"native-header\">\n+ <ion-toolbar><ion-title>Native Header</ion-title></ion-toolbar>\n+ </ion-header>\n
",
"headings": [
{
"id": "%E3%82%BB%E3%83%BC%E3%83%95%E3%82%A8%E3%83%AA%E3%82%A2%E7%94%A8%E3%81%AB-hidden-%E3%81%AA-header-%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B%E5%BF%85%E8%A6%81%E3%81%8C%E3%81%82%E3%82%8B%E3%81%AE%E3%81%AF%E3%81%AA%E3%81%9C%E3%81%A7%E3%81%99%E3%81%8B%EF%BC%9F",
diff --git a/projects/docs/src/app/generated/projects/stripe.en.generated.ts b/projects/docs/src/app/generated/projects/stripe.en.generated.ts
index 2842a93..014aa9a 100644
--- a/projects/docs/src/app/generated/projects/stripe.en.generated.ts
+++ b/projects/docs/src/app/generated/projects/stripe.en.generated.ts
@@ -9,7 +9,8 @@ export const PROJECT = {
"category": "capacitor-plugins",
"icon": "payments",
"version": "8.2.1",
- "description": "Native Stripe payments for Capacitor applications.",
+ "seoTitle": "Capacitor Stripe Plugin Documentation | rdlabo",
+ "description": "Integrate Stripe PaymentSheet, Apple Pay, and Google Pay in Capacitor apps with @capacitor-community/stripe for iOS, Android, and web.",
"headline": "Accept Stripe payments in Capacitor apps",
"overview": "Present native PaymentSheet and PaymentFlow, accept Apple Pay and Google Pay, and integrate payments on the web from the same Capacitor codebase.",
"featuresHeading": "What you can build",
@@ -40,6 +41,9 @@ export const PROJECT = {
{
"title": "Configuration",
"navTitle": "Configuration",
+ "seoTitle": "Configure Capacitor Stripe for iOS, Android, and Web | rdlabo",
+ "seoDescription": "Configure @capacitor-community/stripe with a publishable key and platform settings before presenting PaymentSheet, Apple Pay, or Google Pay.",
+ "updatedAt": "2026-08-31",
"slug": "configuration",
"file": "configuration.md",
"section": "Quickstart",
@@ -689,6 +693,9 @@ export const PROJECT = {
{
"title": "Apple Pay",
"navTitle": "Apple Pay",
+ "seoTitle": "Capacitor Stripe Apple Pay Integration | rdlabo",
+ "seoDescription": "Create, present, and confirm Apple Pay payments in a Capacitor app with @capacitor-community/stripe on supported Apple devices.",
+ "updatedAt": "2026-08-31",
"slug": "apple-pay",
"file": "apple-pay.md",
"section": "Methods",
@@ -883,6 +890,9 @@ export const PROJECT = {
{
"title": "Google Pay",
"navTitle": "Google Pay",
+ "seoTitle": "Capacitor Stripe Google Pay Integration | rdlabo",
+ "seoDescription": "Create, present, and confirm Google Pay payments in a Capacitor app with @capacitor-community/stripe on supported Android devices.",
+ "updatedAt": "2026-08-31",
"slug": "google-pay",
"file": "google-pay.md",
"section": "Methods",
diff --git a/projects/docs/src/app/generated/projects/stripe.ja.generated.ts b/projects/docs/src/app/generated/projects/stripe.ja.generated.ts
index 07fa9f8..ee704f6 100644
--- a/projects/docs/src/app/generated/projects/stripe.ja.generated.ts
+++ b/projects/docs/src/app/generated/projects/stripe.ja.generated.ts
@@ -9,7 +9,8 @@ export const PROJECT = {
"category": "capacitor-plugins",
"icon": "payments",
"version": "8.2.1",
- "description": "Capacitor アプリで Stripe のネイティブ決済を利用するためのプラグイン。",
+ "seoTitle": "Capacitor Stripe プラグイン ドキュメント | rdlabo",
+ "description": "Capacitorアプリに@capacitor-community/stripeを導入し、iOS・Android・WebでPaymentSheet、Apple Pay、Google Payを実装するためのドキュメント。",
"headline": "CapacitorアプリでStripe決済を受け付ける",
"overview": "同じCapacitorコードベースからネイティブのPaymentSheetとPaymentFlow、Apple Pay、Google Pay、Web決済を利用できます。",
"featuresHeading": "実装できること",
@@ -40,6 +41,9 @@ export const PROJECT = {
{
"title": "プラットフォーム設定",
"navTitle": "設定",
+ "seoTitle": "Capacitor StripeのiOS・Android・Web設定 | rdlabo",
+ "seoDescription": "@capacitor-community/stripeに公開可能キーと各Platformの設定を追加し、PaymentSheet、Apple Pay、Google Payを利用する準備をします。",
+ "updatedAt": "2026-08-31",
"slug": "configuration",
"file": "configuration.md",
"section": "クイックスタート",
@@ -689,6 +693,9 @@ export const PROJECT = {
{
"title": "Apple Pay",
"navTitle": "Apple Pay",
+ "seoTitle": "Capacitor StripeでApple Payを実装 | rdlabo",
+ "seoDescription": "@capacitor-community/stripeを使い、対応するApple端末のCapacitorアプリでApple Pay決済を作成・表示・確定します。",
+ "updatedAt": "2026-08-31",
"slug": "apple-pay",
"file": "apple-pay.md",
"section": "メソッド",
@@ -883,6 +890,9 @@ export const PROJECT = {
{
"title": "Google Pay",
"navTitle": "Google Pay",
+ "seoTitle": "Capacitor StripeでGoogle Payを実装 | rdlabo",
+ "seoDescription": "@capacitor-community/stripeを使い、対応するAndroid端末のCapacitorアプリでGoogle Pay決済を作成・表示・確定します。",
+ "updatedAt": "2026-08-31",
"slug": "google-pay",
"file": "google-pay.md",
"section": "メソッド",
diff --git a/projects/docs/src/ionic-angular-scroll-header/docs/ja/ion-content.md b/projects/docs/src/ionic-angular-scroll-header/docs/ja/ion-content.md
index 55d3699..e860c77 100644
--- a/projects/docs/src/ionic-angular-scroll-header/docs/ja/ion-content.md
+++ b/projects/docs/src/ionic-angular-scroll-header/docs/ja/ion-content.md
@@ -4,7 +4,7 @@ code: []
scrollActiveLine: []
---
-Ionic Content に Scroll 連動 Header を付けます。[インストール](/docs/readme#インストール) のあとで呼び出します。
+Ionic Content に Scroll 連動 Header を付けます。[インストール](/docs/readme#インストール) のあとで呼び出します。Safe Area用の非表示Headerと常時表示するNative Headerの使い分けは、[Safe Areaガイド](/docs/safe-area)を参照してください。
- Demo: https://rdlabo-ionic-angular-library.netlify.app/main/scroll-header
- Source: https://github.com/rdlabo-dev/ionic-angular-library/blob/v21.7.0/projects/demo/src/app/scroll-header/scroll-header.page.html
diff --git a/projects/docs/src/ionic-angular-scroll-header/docs/ja/safe-area.md b/projects/docs/src/ionic-angular-scroll-header/docs/ja/safe-area.md
index a751828..490a0ad 100644
--- a/projects/docs/src/ionic-angular-scroll-header/docs/ja/safe-area.md
+++ b/projects/docs/src/ionic-angular-scroll-header/docs/ja/safe-area.md
@@ -6,6 +6,8 @@ scrollActiveLine: []
Safe Area 用の非表示 Header と常時表示 Native Header です。
+まず[IonContentガイド](/docs/ion-content)のScroll連動Headerを設定し、このページのHeader構成を用途に応じて選択してください。
+
## セーフエリア用に hidden な Header を設定する必要があるのはなぜですか?
もちろん、次のように ion-content にセーフエリアを設定することもできます。
diff --git a/projects/web-site/public/sitemap.xml b/projects/web-site/public/sitemap.xml
index 92bf1f3..eaf6f34 100644
--- a/projects/web-site/public/sitemap.xml
+++ b/projects/web-site/public/sitemap.xml
@@ -11,7 +11,8 @@
https://rdlabo.dev/articles/archive/2020
https://rdlabo.dev/articles/ionic-themes-ionic9-major-update
https://rdlabo.dev/articles/ionic-theme-md3
- https://rdlabo.dev/articles/ionic-9-components-got-better
+ https://rdlabo.dev/articles/ionic-9-components-got-better
+ 2026-08-31
https://rdlabo.dev/articles/capawesome-live-update-release-cycle
https://rdlabo.dev/articles/mobile-app-live-updates
https://rdlabo.dev/articles/f3f96d96bd5e87
diff --git a/projects/web-site/src/app/components/article-sidebar/article-sidebar.spec.ts b/projects/web-site/src/app/components/article-sidebar/article-sidebar.spec.ts
index 5964889..7346983 100644
--- a/projects/web-site/src/app/components/article-sidebar/article-sidebar.spec.ts
+++ b/projects/web-site/src/app/components/article-sidebar/article-sidebar.spec.ts
@@ -36,14 +36,16 @@ describe('ArticleSidebar', () => {
);
expect(links.map((link) => link.textContent?.trim())).toEqual([
+ 'Ionic Docs Japanese',
'Ionic Theme iOS26',
'Ionic Theme MD3',
]);
expect(links.map((link) => link.getAttribute('href'))).toEqual([
+ '/articles?library=ionic-docs',
'/articles?library=ionic-theme-ios26',
'/articles?library=ionic-theme-md3',
]);
- expect(root.querySelectorAll('.article-sidebar__category-icon')).toHaveLength(2);
+ expect(root.querySelectorAll('.article-sidebar__category-icon')).toHaveLength(3);
expect(
Array.from(root.querySelectorAll('.article-sidebar__category-icon')).every(
(icon) => icon.getAttribute('aria-hidden') === 'true',
diff --git a/projects/web-site/src/app/generated/article-catalog.generated.ts b/projects/web-site/src/app/generated/article-catalog.generated.ts
index c4e52e2..dcf2470 100644
--- a/projects/web-site/src/app/generated/article-catalog.generated.ts
+++ b/projects/web-site/src/app/generated/article-catalog.generated.ts
@@ -49,10 +49,18 @@ export const ARTICLE_SUMMARIES = [
"slug": "ionic-9-components-got-better",
"title": "Ionic 9 Is Here! Web Standardization Takes a Big Step Forward — Five Major Changes",
"description": "Ionic Framework 9 highlights five changes that matter in day-to-day app development: rich Select options, Font Icons in ion-icon, ion-img deprecation, cleaner form controls, and more accessible sheet modal handles.",
+ "updatedAt": "2026-08-31",
"image": "https://rdlabo.dev/article-images/ionic-9-components-got-better.svg",
"imageWidth": 1200,
"imageHeight": 630,
"emoji": "🚀",
+ "relatedLibraries": [
+ {
+ "id": "ionic-docs",
+ "name": "Ionic Docs Japanese",
+ "url": "https://ionicframework.jp/docs/"
+ }
+ ],
"sourceName": "Zenn",
"originalUrl": "https://zenn.dev/rdlabo/articles/ionic-9-components-got-better",
"publishedAt": "2026-08-20T23:21:47.000Z",
diff --git a/projects/web-site/src/articles/ionic-9-components-got-better.md b/projects/web-site/src/articles/ionic-9-components-got-better.md
index 00bb920..b7fe209 100644
--- a/projects/web-site/src/articles/ionic-9-components-got-better.md
+++ b/projects/web-site/src/articles/ionic-9-components-got-better.md
@@ -2,6 +2,9 @@
title: "Ionic 9 Is Here! Web Standardization Takes a Big Step Forward — Five Major Changes"
description: "Ionic Framework 9 highlights five changes that matter in day-to-day app development: rich Select options, Font Icons in ion-icon, ion-img deprecation, cleaner form controls, and more accessible sheet modal handles."
zennSlug: ionic-9-components-got-better
+updatedAt: "2026-08-31"
+relatedLibraries:
+ - ionic-docs
emoji: "🚀"
---
diff --git a/scripts/article-relations.test.ts b/scripts/article-relations.test.ts
index fd6d8e6..e96c89b 100644
--- a/scripts/article-relations.test.ts
+++ b/scripts/article-relations.test.ts
@@ -1,9 +1,7 @@
import assert from 'node:assert/strict';
-import { mkdtemp, rm, writeFile } from 'node:fs/promises';
-import { tmpdir } from 'node:os';
-import { join } from 'node:path';
+import { readFile } from 'node:fs/promises';
import test from 'node:test';
-import { loadRelatedArticlesByLibrary, parseRelatedLibraryIds } from './article-relations';
+import { groupRelatedArticlesByLibrary, parseRelatedLibraryIds } from './article-relations';
test('normalizes, deduplicates, and validates related library IDs', () => {
assert.deepEqual(
@@ -28,76 +26,74 @@ test('normalizes, deduplicates, and validates related library IDs', () => {
);
});
-test('groups articles by library in deterministic reverse publication order', async () => {
- const directory = await mkdtemp(join(tmpdir(), 'article-relations-'));
- try {
- await Promise.all([
- writeFile(
- join(directory, 'z-last.md'),
- `---
-title: Last
-description: Last description
-slug: last
-publishedDate: "2026-08-24"
-relatedLibraries:
- - ionic-theme-md3
----
-Body
-`,
- ),
- writeFile(
- join(directory, 'a-first.md'),
- `---
-title: First
-description: First description
-zennSlug: first
-publishedDate: "2026-08-23"
-relatedLibraries:
- - " ionic-theme-md3 "
- - ionic-theme-ios26
- - ionic-theme-md3
----
-Body
-`,
- ),
- writeFile(join(directory, 'ignored.md'), '---\ntitle: Ignored\n---\nBody\n'),
- ]);
+test('groups generated article summaries by library in reverse publication order', () => {
+ const related = groupRelatedArticlesByLibrary([
+ {
+ slug: 'first',
+ title: 'First',
+ description: 'First description',
+ publishedDate: '2026-08-23',
+ relatedLibraries: [
+ { id: 'ionic-theme-md3' },
+ { id: 'ionic-theme-ios26' },
+ { id: 'ionic-theme-md3' },
+ ],
+ },
+ {
+ slug: 'last',
+ title: 'Last',
+ description: 'Last description',
+ publishedDate: '2026-08-24',
+ relatedLibraries: [{ id: 'ionic-theme-md3' }],
+ },
+ {
+ slug: 'ignored',
+ title: 'Ignored',
+ description: 'Ignored description',
+ publishedDate: '2026-08-25',
+ },
+ ]);
+ assert.deepEqual(
+ related.get('ionic-theme-md3')?.map((article) => article.slug),
+ ['last', 'first'],
+ );
+ assert.deepEqual(related.get('ionic-theme-ios26'), [
+ {
+ slug: 'first',
+ title: 'First',
+ description: 'First description',
+ publishedDate: '2026-08-23',
+ url: 'https://rdlabo.dev/articles/first',
+ },
+ ]);
+});
- const related = await loadRelatedArticlesByLibrary(directory);
- assert.deepEqual(
- related.get('ionic-theme-md3')?.map((article) => article.slug),
- ['last', 'first'],
- );
- assert.deepEqual(related.get('ionic-theme-ios26'), [
- {
- slug: 'first',
- title: 'First',
- description: 'First description',
- publishedDate: '2026-08-23',
- url: 'https://rdlabo.dev/articles/first',
- },
- ]);
- } finally {
- await rm(directory, { recursive: true, force: true });
- }
+test('rejects malformed generated related article metadata', () => {
+ assert.throws(
+ () =>
+ groupRelatedArticlesByLibrary([
+ {
+ slug: 'invalid',
+ title: ' ',
+ description: 'Description',
+ publishedDate: '2026-08-24',
+ relatedLibraries: [{ id: 'ionic-theme-md3' }],
+ },
+ ]),
+ /must declare a non-empty title/,
+ );
});
-test('rejects malformed related article metadata', async () => {
- const directory = await mkdtemp(join(tmpdir(), 'article-relations-invalid-'));
- try {
- await writeFile(
- join(directory, 'invalid.md'),
- `---
-title: " "
-description: Description
-slug: invalid
-relatedLibraries:
- - ionic-theme-md3
----
-`,
- );
- await assert.rejects(loadRelatedArticlesByLibrary(directory), /must declare a non-empty title/);
- } finally {
- await rm(directory, { recursive: true, force: true });
+test('generates article metadata before documentation through the public docs entrypoint', async () => {
+ const packageJson = JSON.parse(
+ await readFile(new URL('../package.json', import.meta.url), 'utf8'),
+ ) as { scripts: Record };
+ assert.equal(
+ packageJson.scripts['docs:generate'],
+ 'npm run articles:generate && npm run docs:generate:content',
+ );
+ assert.equal(packageJson.scripts['docs:generate:content'], 'tsx scripts/generate-docs.ts');
+ for (const script of ['prestart', 'prestart:ja', 'prebuild:docs', 'pretest']) {
+ assert.equal(packageJson.scripts[script], 'npm run docs:generate', script);
}
});
diff --git a/scripts/article-relations.ts b/scripts/article-relations.ts
index fe4f758..0106583 100644
--- a/scripts/article-relations.ts
+++ b/scripts/article-relations.ts
@@ -1,6 +1,3 @@
-import { readFile, readdir } from 'node:fs/promises';
-import { join } from 'node:path';
-import fm from 'front-matter';
import { projectDefinitions } from './project-manifest';
export interface RelatedArticle {
@@ -28,40 +25,36 @@ export function parseRelatedLibraryIds(value: unknown, file: string): string[] {
return ids;
}
-function requiredArticleField(value: unknown, field: string, file: string): string {
+interface RelatedArticleSummary {
+ slug: string;
+ title: string;
+ description: string;
+ publishedDate: string;
+ relatedLibraries?: readonly { id: string }[];
+}
+
+function requiredArticleField(value: unknown, field: string, article: string): string {
if (typeof value !== 'string' || !value.trim()) {
- throw new Error(`${file} with relatedLibraries must declare a non-empty ${field}`);
+ throw new Error(`${article} with relatedLibraries must declare a non-empty ${field}`);
}
return value.trim();
}
-export async function loadRelatedArticlesByLibrary(
- articlesDirectory: string,
-): Promise