From 53e68c3449e47da21c192ce3df746ee0eb717301 Mon Sep 17 00:00:00 2001
From: seieric <30688855+seieric@users.noreply.github.com>
Date: Thu, 30 Jul 2026 16:57:31 +0900
Subject: [PATCH 1/4] =?UTF-8?q?feat:=20OGP=E7=94=BB=E5=83=8F=E3=82=92front?=
=?UTF-8?q?matter=E3=81=A7=E6=8C=87=E5=AE=9A=E5=8F=AF=E8=83=BD=E3=81=AB?=
=?UTF-8?q?=E3=81=99=E3=82=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/layouts/Layout.astro | 79 ++++++-----------------------------
src/layouts/SEO.astro | 89 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 102 insertions(+), 66 deletions(-)
create mode 100644 src/layouts/SEO.astro
diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro
index 05ccf0cdf1..a06f8dd64a 100644
--- a/src/layouts/Layout.astro
+++ b/src/layouts/Layout.astro
@@ -1,18 +1,17 @@
---
-import { SEO, type Props as SEOProps } from "astro-seo";
+import SEO, { type OgpImage } from "./SEO.astro";
import GoogleAnalytics from "./GoogleAnalytics.astro";
import MicrosoftClarity from "./MicrosoftClarity.astro";
import Header from "./Header/index.astro";
import Footer from "./Footer/index.astro";
import Toc from "./Toc.astro";
import "@styles/layout.scss";
-import type { MDXLayoutProps, MarkdownHeading } from "astro";
+import type { MDXLayoutProps } from "astro";
import Author, { type Author as AuthorProps } from "./Author.astro";
import Breadcrumb from "./Breadcrumb.astro";
import type { Breadcrumb as BreadcrumbProps } from "./resolve-breadcrumb";
import Markdown from "@components/utils/Markdown.astro";
import type { Lang } from "@components/types";
-import { parse as parsePath } from "path";
import "@fontsource/material-icons";
import "@fontsource-variable/open-sans";
import resolveBreadcrumb from "./resolve-breadcrumb";
@@ -33,36 +32,20 @@ export interface Frontmatter {
redirect_to?: string;
author?: AuthorProps;
breadcrumb?: BreadcrumbProps;
+ ogpImage?: OgpImage;
}
-function createDefaultDescription(
- lang: Lang,
- headings: MarkdownHeading[],
-): string {
- return (
- (
- {
- ja: "目次: ",
- en: "Table of Contents: ",
- }[lang] +
- headings
- .filter(({ depth }) => depth === 2)
- .map(({ text }) => text)
- .join("; ")
- ).slice(0, 97) + "..."
- );
-}
-
-const { frontmatter, headings, file } = Astro.props;
+const { frontmatter, headings } = Astro.props;
const {
title,
- description = createDefaultDescription(frontmatter.lang, headings),
+ description,
lang,
h1,
top,
support,
author,
breadcrumb,
+ ogpImage,
} = frontmatter;
const displayToc = !top && (frontmatter.toc ?? true) && headings.length > 0;
@@ -77,53 +60,11 @@ const htmlAttributes = {
},
}[lang];
-const locale = {
- en: "en_US",
- ja: "ja_JP",
-}[lang];
-
const gaid = "G-ZM6H96EWBD";
const clarityProjectId = "vat2444uow";
const canonicalUrl = Astro.url;
-const seoProps: SEOProps = {
- title,
- titleTemplate: "%s | utelecon",
- titleDefault: "utelecon",
- description,
- charset: "UTF-8",
- canonical: canonicalUrl.href,
-};
-
-const ogpImagePath = {
- en: "/assets/images/ogp_en.png",
- ja: "/assets/images/ogp.png",
-}[lang];
-
-if (title) {
- seoProps.openGraph = {
- basic: {
- title,
- type: "website",
- url: canonicalUrl.href,
- image: new URL(ogpImagePath, Astro.site).href,
- },
- optional: {
- description,
- locale,
- siteName: "utelecon",
- },
- image: {
- alt: "utelecon",
- },
- };
- seoProps.twitter = {
- title,
- description,
- };
-}
-
const resolvedBreadcrumb =
breadcrumb && (await resolveBreadcrumb(Astro.url, breadcrumb));
---
@@ -131,7 +72,13 @@ const resolvedBreadcrumb =
-
+
diff --git a/src/layouts/SEO.astro b/src/layouts/SEO.astro
new file mode 100644
index 0000000000..80fe5af491
--- /dev/null
+++ b/src/layouts/SEO.astro
@@ -0,0 +1,89 @@
+---
+import { SEO as AstroSEO, type Props as SEOProps } from "astro-seo";
+import type { MarkdownHeading } from "astro";
+import type { Lang } from "@components/types";
+
+interface Props {
+ title?: string;
+ description?: string;
+ lang: Lang;
+ headings?: MarkdownHeading[];
+ ogpImage?: OgpImage;
+}
+
+export interface OgpImage {
+ ja?: string;
+ en?: string;
+}
+
+const { title, description, lang, headings = [], ogpImage } = Astro.props;
+
+function createDefaultDescription(
+ lang: Lang,
+ headings: MarkdownHeading[],
+): string {
+ return (
+ (
+ {
+ ja: "目次: ",
+ en: "Table of Contents: ",
+ }[lang] +
+ headings
+ .filter(({ depth }) => depth === 2)
+ .map(({ text }) => text)
+ .join("; ")
+ ).slice(0, 97) + "..."
+ );
+}
+
+const resolvedDescription =
+ description ?? createDefaultDescription(lang, headings);
+
+const locale = {
+ en: "en_US",
+ ja: "ja_JP",
+}[lang];
+
+const canonicalUrl = Astro.url;
+
+const seoProps: SEOProps = {
+ title,
+ titleTemplate: "%s | utelecon",
+ titleDefault: "utelecon",
+ description,
+ charset: "UTF-8",
+ canonical: canonicalUrl.href,
+};
+
+const defaultOgpImagePath = {
+ en: "/assets/images/ogp_en.png",
+ ja: "/assets/images/ogp.png",
+}[lang];
+
+const ogpImagePath = ogpImage?.[lang] ?? defaultOgpImagePath;
+
+if (title) {
+ seoProps.openGraph = {
+ basic: {
+ title,
+ type: "website",
+ url: canonicalUrl.href,
+ image: new URL(ogpImagePath, Astro.site).href,
+ },
+ optional: {
+ description: resolvedDescription,
+ locale,
+ siteName: "utelecon",
+ },
+ image: {
+ alt: "utelecon",
+ },
+ };
+ seoProps.twitter = {
+ title,
+ description: resolvedDescription,
+ };
+}
+---
+
+
From 751bfc1ed8b2d93d944033d01e9e2aeb2e752131 Mon Sep 17 00:00:00 2001
From: seieric <30688855+seieric@users.noreply.github.com>
Date: Thu, 30 Jul 2026 17:06:55 +0900
Subject: [PATCH 2/4] =?UTF-8?q?add:=20README=E3=81=ABOGP=E7=94=BB=E5=83=8F?=
=?UTF-8?q?=E8=A8=AD=E5=AE=9A=E3=81=AE=E8=AA=AC=E6=98=8E=E3=82=92=E8=BF=BD?=
=?UTF-8?q?=E5=8A=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/README.md b/README.md
index 18757bff74..64523af4cd 100644
--- a/README.md
+++ b/README.md
@@ -39,6 +39,7 @@ Markdownファイルのフロントマターにかける設定は以下の通り
- `name`:著者名.任意.
- `breadcrumb`:ページ上部のパンくずリストを定義する.詳しくは[後述](#パンくずリストの表示).
- `redirect_from`・`redirect_to`:リダイレクトの設定.詳しくは[後述](#redirect_from--redirect_to).
+- `ogpImage`: ページに任意のOGP画像を設定する. 詳しくは[後述](#任意のOGP画像を設定する)
## Scripts
@@ -271,6 +272,25 @@ pattern: "^\/utol\/"
---
```
+### 任意のOGP画像を設定する
+
+`ogpImage`をMarkdownのfrontmatterに記述することで,SNS共有時などに表示されるOGP画像をページごとに個別設定できます.
+言語ごとに任意のOGP画像を設定可能となっており,設定がない場合はデフォルトのOGP画像が利用されます.
+
+指定する画像は`public/assets/images/`以下に配置し,`/assets/images/custom_ogp_ja.png`のように指定してください.
+
+### 記述例
+
+```md
+---
+title: "記事のタイトル"
+lang: "ja"
+ogpImage:
+ ja: "/assets/images/custom_ogp_ja.png"
+ en: "/assets/images/custom_ogp_en.png"
+---
+```
+
### ボタン・タブUIを利用したい場合
[多要素認証の初期設定手順](https://utelecon.adm.u-tokyo.ac.jp/utokyo_account/mfa/initial/)や[サポート窓口](https://utelecon.adm.u-tokyo.ac.jp/support/)のページでは,ボタンとタブを用いたUIが利用されており,ユーザの選択によって表示内容を切り替えたり,ボタンをクリックして別のページに遷移したりすることができます.
From 5eb7a662bb5b72c0d159c828807b63721c40a4b2 Mon Sep 17 00:00:00 2001
From: seieric <30688855+seieric@users.noreply.github.com>
Date: Fri, 31 Jul 2026 18:11:36 +0900
Subject: [PATCH 3/4] =?UTF-8?q?fix=20=E4=B8=8D=E8=A6=81=E3=81=AA=E8=A8=80?=
=?UTF-8?q?=E8=AA=9E=E5=88=87=E6=9B=BF=E3=82=92=E5=89=8A=E9=99=A4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/layouts/Layout.astro | 4 ++--
src/layouts/SEO.astro | 9 ++-------
2 files changed, 4 insertions(+), 9 deletions(-)
diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro
index a06f8dd64a..b8353c111a 100644
--- a/src/layouts/Layout.astro
+++ b/src/layouts/Layout.astro
@@ -1,5 +1,5 @@
---
-import SEO, { type OgpImage } from "./SEO.astro";
+import SEO from "./SEO.astro";
import GoogleAnalytics from "./GoogleAnalytics.astro";
import MicrosoftClarity from "./MicrosoftClarity.astro";
import Header from "./Header/index.astro";
@@ -32,7 +32,7 @@ export interface Frontmatter {
redirect_to?: string;
author?: AuthorProps;
breadcrumb?: BreadcrumbProps;
- ogpImage?: OgpImage;
+ ogpImage?: string;
}
const { frontmatter, headings } = Astro.props;
diff --git a/src/layouts/SEO.astro b/src/layouts/SEO.astro
index 80fe5af491..9163b360a5 100644
--- a/src/layouts/SEO.astro
+++ b/src/layouts/SEO.astro
@@ -8,12 +8,7 @@ interface Props {
description?: string;
lang: Lang;
headings?: MarkdownHeading[];
- ogpImage?: OgpImage;
-}
-
-export interface OgpImage {
- ja?: string;
- en?: string;
+ ogpImage?: string;
}
const { title, description, lang, headings = [], ogpImage } = Astro.props;
@@ -60,7 +55,7 @@ const defaultOgpImagePath = {
ja: "/assets/images/ogp.png",
}[lang];
-const ogpImagePath = ogpImage?.[lang] ?? defaultOgpImagePath;
+const ogpImagePath = ogpImage ?? defaultOgpImagePath;
if (title) {
seoProps.openGraph = {
From b2cb559923a72b2d466879723d77d4f25f86bd3e Mon Sep 17 00:00:00 2001
From: seieric <30688855+seieric@users.noreply.github.com>
Date: Fri, 31 Jul 2026 18:12:32 +0900
Subject: [PATCH 4/4] update README
---
README.md | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/README.md b/README.md
index 64523af4cd..dc62a7f06d 100644
--- a/README.md
+++ b/README.md
@@ -274,10 +274,9 @@ pattern: "^\/utol\/"
### 任意のOGP画像を設定する
-`ogpImage`をMarkdownのfrontmatterに記述することで,SNS共有時などに表示されるOGP画像をページごとに個別設定できます.
-言語ごとに任意のOGP画像を設定可能となっており,設定がない場合はデフォルトのOGP画像が利用されます.
+`ogpImage`をMarkdownのfrontmatterに記述することで,SNS共有時などに表示されるOGP画像をページごとに個別設定できます.設定がない場合はデフォルトのOGP画像が利用されます.
-指定する画像は`public/assets/images/`以下に配置し,`/assets/images/custom_ogp_ja.png`のように指定してください.
+指定する画像は`public/assets/images/`以下に配置し,`/assets/images/custom_ogp.png`のように指定してください.
### 記述例
@@ -285,9 +284,7 @@ pattern: "^\/utol\/"
---
title: "記事のタイトル"
lang: "ja"
-ogpImage:
- ja: "/assets/images/custom_ogp_ja.png"
- en: "/assets/images/custom_ogp_en.png"
+ogpImage: "/assets/images/custom_ogp.png"
---
```