From 6c4e56b046b3c4696fa9046fae2eb6ec8032ce2b Mon Sep 17 00:00:00 2001 From: Ciffelia Date: Thu, 7 Dec 2023 21:49:20 +0900 Subject: [PATCH 1/3] =?UTF-8?q?``=E3=81=AE`src`=E3=81=AB=E5=A4=96?= =?UTF-8?q?=E9=83=A8=E7=94=BB=E5=83=8F=E3=81=AEURL=E3=82=92=E6=B8=A1?= =?UTF-8?q?=E3=81=9B=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/Image.astro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/common/Image.astro b/src/components/common/Image.astro index 7819f4f..3cab92d 100644 --- a/src/components/common/Image.astro +++ b/src/components/common/Image.astro @@ -4,7 +4,7 @@ import type { HTMLAttributes } from 'astro/types' import { getImage } from 'astro:assets' type Props = Omit, 'src' | 'srcset'> & { - src: ImageMetadata | Promise<{ default: ImageMetadata }> + src: string | ImageMetadata | Promise<{ default: ImageMetadata }> widths?: number[] } From 337594fff62828be81498c07a9e351c9d73f582a Mon Sep 17 00:00:00 2001 From: Ciffelia Date: Thu, 7 Dec 2023 21:55:40 +0900 Subject: [PATCH 2/3] =?UTF-8?q?=E7=94=BB=E5=83=8F=E3=81=A8=E8=91=97?= =?UTF-8?q?=E8=80=85=E3=81=AE=E3=82=A2=E3=82=A4=E3=82=B3=E3=83=B3=E3=81=AB?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E3=81=A7=E3=81=8D=E3=82=8B=E7=94=BB=E5=83=8F?= =?UTF-8?q?=E3=83=95=E3=82=A9=E3=83=BC=E3=83=9E=E3=83=83=E3=83=88=E3=82=92?= =?UTF-8?q?=E5=A2=97=E3=82=84=E3=81=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README_BLOG.md | 106 +++++++++--------- .../blog/default_user.svg => avatar.svg} | 2 +- src/assets/{icons/blog => }/hashtag.svg | 2 +- src/components/blog/icon/AuthorIcon.astro | 46 +++----- src/components/blog/icon/TagIcon.astro | 33 ++---- src/content/config.ts | 52 +++------ src/content/tags/arduino.json | 5 +- .../icons/blog => content/tags}/arduino.svg | 0 src/content/tags/astro.json | 5 +- .../tags/astro.svg} | 0 src/content/tags/csharp.json | 5 +- .../icons/blog => content/tags}/csharp.svg | 0 src/content/tags/discord-bot.json | 5 +- .../tags/discord-bot.svg} | 0 src/content/tags/docker.json | 5 +- .../icons/blog => content/tags}/docker.svg | 0 src/content/tags/dotnet.json | 5 +- .../tags/dotnet.svg} | 0 src/content/tags/electronic-dictionary.json | 5 +- .../tags/electronic-dictionary.svg} | 0 src/content/tags/git.json | 5 +- .../icons/blog => content/tags}/git.svg | 0 src/content/tags/go.json | 5 +- .../Go-Logo_Aqua.svg => content/tags/go.svg} | 0 src/content/tags/markdown.json | 5 +- .../tags/markdown.svg} | 0 src/content/tags/python.json | 5 +- .../tags/python.svg} | 0 src/content/tags/rest-api.json | 5 +- .../tags/rest-api.svg} | 0 src/content/tags/rust.json | 5 +- .../tags/rust.svg} | 0 src/content/tags/unity.json | 5 +- .../tags/unity.svg} | 0 src/pages/blog/authors/[slug]/index.astro | 28 +++-- src/pages/blog/authors/[slug]/ogp.png.ts | 38 ------- src/pages/blog/tags/[slug]/index.astro | 16 ++- src/pages/blog/tags/[slug]/ogp.png.ts | 33 ------ src/utils/getImageWithSvgConvert.ts | 29 +++++ 39 files changed, 162 insertions(+), 293 deletions(-) rename src/assets/{icons/blog/default_user.svg => avatar.svg} (70%) rename src/assets/{icons/blog => }/hashtag.svg (95%) rename src/{assets/icons/blog => content/tags}/arduino.svg (100%) rename src/{assets/icons/blog/astro-icon-dark.svg => content/tags/astro.svg} (100%) rename src/{assets/icons/blog => content/tags}/csharp.svg (100%) rename src/{assets/icons/blog/discord-mark-black.svg => content/tags/discord-bot.svg} (100%) rename src/{assets/icons/blog => content/tags}/docker.svg (100%) rename src/{assets/icons/blog/dotnet-logo.svg => content/tags/dotnet.svg} (100%) rename src/{assets/icons/blog/laptop.svg => content/tags/electronic-dictionary.svg} (100%) rename src/{assets/icons/blog => content/tags}/git.svg (100%) rename src/{assets/icons/blog/Go-Logo_Aqua.svg => content/tags/go.svg} (100%) rename src/{assets/icons/blog/Markdown-mark.svg => content/tags/markdown.svg} (100%) rename src/{assets/icons/blog/python-logo-only.svg => content/tags/python.svg} (100%) rename src/{assets/icons/blog/rest-api-icon.svg => content/tags/rest-api.svg} (100%) rename src/{assets/icons/blog/rust-logo-blk.svg => content/tags/rust.svg} (100%) rename src/{assets/icons/blog/U_ProfileIcon_Positive.svg => content/tags/unity.svg} (100%) delete mode 100644 src/pages/blog/authors/[slug]/ogp.png.ts delete mode 100644 src/pages/blog/tags/[slug]/ogp.png.ts create mode 100644 src/utils/getImageWithSvgConvert.ts diff --git a/README_BLOG.md b/README_BLOG.md index bdecb7e..d0cd78b 100644 --- a/README_BLOG.md +++ b/README_BLOG.md @@ -2,7 +2,7 @@ OUCC BLOG の仕様について記載しています。何もわからない場合はサーバー係に投稿したい Markdown ファイルを渡してください。 -ブログの投稿を行う際はブランチ名が `blog/` で始まるブランチを作成し作業してください。このブランチではブログの投稿に関する作業以外は禁止されていますが、後述するようにCIによる支援が得られます。 +ブログの投稿を行う際はブランチ名が `blog/` で始まるブランチを作成し作業してください。このブランチではブログの投稿に関する作業以外は禁止されていますが、後述するように投稿日時や更新日時が自動で生成されます。 ブログに関して作業することを明示しつつこの制約を受けたくない場合は、ブランチ名が `blog/admin/` で始まるブランチで作業してください。 @@ -20,6 +20,8 @@ tags: - タグ2 - タグ3 --- + +これは記事本文です。Markdownで文章を書くことができます。 ``` 画像ファイルは `src/content/blogs` に新しいディレクトリを作成してそこに配置するか、または外部においてURLで指定してください。 @@ -28,7 +30,7 @@ tags: ## 記事のメタ情報 -記事のメタ情報には投稿日時と更新日時が含まれています。これは `blog/` から始まるブランチで Pull Request を出すと自動的に更新されます。 +`src/content/blog-metas`にある記事のメタ情報には投稿日時と更新日時が含まれています。これは `blog/` から始まるブランチで Pull Request を出すと自動的に作成・更新されます。 以下のようにコマンドを使うことで手動で更新することもできます。 @@ -36,45 +38,45 @@ tags: $ npm run update-blogmeta -- src/content/blogs/NEW-POST1.md src/content/blogs/NEW-POST2.md ``` -## 著者 +## 著者の追加 + +`src/content/authors` に JSON ファイルを追加することで著者ページを作ることができます。ファイル名は記事の `author` で指定する際の値となるので自身のIDなどわかりやすい名前にしてください。 -`src/content/authors` に JSON ファイルを追加することで新しいタグを作ることができます。ファイル名は記事の `author` で指定する際の値となるのでわかりやすい名前にすることをおすすめします。 著者のスキーマは以下のとおりです。`name` 以外のプロパティは省略可能です。 -- name : 著者の表示名 +- name : 著者の表示名(必須) - description : 著者の説明 -- github : GitHub アカウントの ID (image を指定しなかった場合、こちらで指定したアカウントのアイコンが使用されます。) -- image : 著者のアイコン - - `svg` は `src/assets/icons/blog` に入っているsvgファイルを指定できます。`name` には拡張子を除いたファイル名を指定してください。 - - `external-url` は外部の画像を指定できます。 - -```ts -interface Author { - name: string - description?: string - github?: string - image?: - | { - type: 'svg' - name: string - } - | { - type: 'external-url' - url: string - } +- github : GitHub アカウントの ID +- image : アイコンの画像ファイル(詳細は後述) + +Example: `src/content/authors/octocat.json` + +```json +{ + "name": "Octocat", + "description": "八本足の猫です。", + "github": "octocat", + "image": "./octocat.svg" } ``` -## タグ +### 著者のアイコン(任意) + +`src/content/authors`に画像ファイルを置き、JSONでファイル名を指定することでアイコンを変更できます。ファイル名はJSONと同じものにしてください。画像フォーマットにはSVG, PNG, JPEG等が使用できます。 + +例えばJSONが`octocat.json`の場合、アイコンのファイル名は`octocat.svg`とし、JSONでは`"image": "./octocat.svg"`と指定してください。 + +なお、画像を指定しなかった場合はGitHubのアイコンが使用されます。 + +## タグの追加 `src/content/tags` に JSON ファイルを追加することで新しいタグを作ることができます。ファイル名は記事の `tags` で指定する際の値となるのでわかりやすい名前にすることをおすすめします。 + タグのスキーマは以下のとおりです。 `name` 以外のプロパティは省略可能です。 -- name : タグの表示名 +- name : タグの表示名(必須) - description : タグの説明 -- image : タグのアイコン - - `svg` は `src/assets/icons/blog` に入っているsvgファイルを指定できます。`name` には拡張子を除いたファイル名を指定してください。 - - `external-url` は外部の画像を指定できます。 +- image : アイコンの画像ファイル(詳細は後述) - site : 公式サイト - url : 公式サイトのURL - text : リンクの表示名 (指定のない場合 `タグ名 - 公式サイト` となります) @@ -85,30 +87,28 @@ interface Author { - url : GitHubのリポジトリのURL - text : リンクの表示名 (指定のない場合 `タグ名 - GitHub` となります) -```ts -interface Tag { - name: string - description?: string - image?: - | { - type: 'svg' - name: string - } - | { - type: 'external-url' - url: string - } - site?: { - url: string - text?: string - } - document?: { - url: string - text?: string - } - github?: { - url: string - text?: string +Example: `src/content/tags/csharp.json` + +```json +{ + "name": "C#", + "description": "C#は、最新のタイプ セーフなオブジェクト指向のプログラミング言語です。 開発者は C# を使用することにより、.NET で稼働する、安全かつ堅牢な多くの種類のアプリケーションを構築できます。", + "image": "./csharp.svg", + "site": { + "url": "https://dotnet.microsoft.com/ja-jp/learn/dotnet/what-is-dotnet" + }, + "document": { + "url": "https://learn.microsoft.com/ja-jp/dotnet/csharp/programming-guide/" + }, + "github": { + "url": "https://github.com/dotnet/runtime", + "text": ".NET Runtime - GitHub" } } ``` + +### タグのアイコン(任意) + +`src/content/tags`に画像ファイルを置き、JSONでファイル名を指定することでアイコンを変更できます。ファイル名はJSONと同じものにしてください。画像フォーマットにはSVG, PNG, JPEG等が使用できます。 + +例えばJSONが`csharp.json`の場合、アイコンのファイル名は`csharp.png`とし、JSONでは`"image": "./csharp.png"`と指定してください。 diff --git a/src/assets/icons/blog/default_user.svg b/src/assets/avatar.svg similarity index 70% rename from src/assets/icons/blog/default_user.svg rename to src/assets/avatar.svg index 9fd8a96..6bbe8a0 100644 --- a/src/assets/icons/blog/default_user.svg +++ b/src/assets/avatar.svg @@ -1,4 +1,4 @@ - + diff --git a/src/assets/icons/blog/hashtag.svg b/src/assets/hashtag.svg similarity index 95% rename from src/assets/icons/blog/hashtag.svg rename to src/assets/hashtag.svg index 5b1a503..6d024d5 100644 --- a/src/assets/icons/blog/hashtag.svg +++ b/src/assets/hashtag.svg @@ -1,4 +1,4 @@ - + diff --git a/src/components/blog/icon/AuthorIcon.astro b/src/components/blog/icon/AuthorIcon.astro index d848f8f..4425f15 100644 --- a/src/components/blog/icon/AuthorIcon.astro +++ b/src/components/blog/icon/AuthorIcon.astro @@ -1,41 +1,21 @@ --- -import Icon from '@/components/common/Icon.astro' -import { unreachable } from '@/utils/unreachable' import type { CollectionEntry } from 'astro:content' +import defaultImage from '@/assets/avatar.svg' +import Image from '@/components/common/Image.astro' type Props = CollectionEntry<'authors'>['data'] & { size: number } const { size, ...author } = Astro.props -const image = - author.image.type === 'svg' && - author.image.name === 'default_user' && - author.github - ? ({ - type: 'external-url', - url: `https://github.com/${author.github}.png`, - } as const) - : author.image +const src = + author.image ?? author.github !== undefined + ? `https://github.com/${author.github}.png` + : defaultImage --- -{ - image.type === 'svg' ? ( - - ) : image.type === 'external-url' ? ( - {`${author.name} - ) : ( - unreachable(image) - ) -} +{`${author.name} diff --git a/src/components/blog/icon/TagIcon.astro b/src/components/blog/icon/TagIcon.astro index 4f2c368..302c070 100644 --- a/src/components/blog/icon/TagIcon.astro +++ b/src/components/blog/icon/TagIcon.astro @@ -1,7 +1,7 @@ --- -import Icon from '@/components/common/Icon.astro' -import { unreachable } from '@/utils/unreachable' import type { CollectionEntry } from 'astro:content' +import defaultImage from '@/assets/hashtag.svg' +import Image from '@/components/common/Image.astro' interface Props { tag: CollectionEntry<'tags'>['data'] @@ -11,25 +11,10 @@ interface Props { const { tag, size } = Astro.props --- -{ - tag.image.type === 'svg' ? ( - - ) : tag.image.type === 'external-url' ? ( - {`${tag.name} - ) : ( - unreachable(tag.image) - ) -} +{`${tag.name} diff --git a/src/content/config.ts b/src/content/config.ts index 54236b9..2f1ae6c 100644 --- a/src/content/config.ts +++ b/src/content/config.ts @@ -32,23 +32,13 @@ const blogsMetaCollection = defineCollection({ const authorsCollection = defineCollection({ type: 'data', - schema: z.object({ - name: z.string().min(1), - description: z.string().optional(), - github: z.string().min(1).optional(), - image: z - .discriminatedUnion('type', [ - z.object({ - type: z.literal('svg'), - name: z.string().min(1), - }), - z.object({ - type: z.literal('external-url'), - url: z.string().url(), - }), - ]) - .default({ type: 'svg', name: 'default_user' }), - }), + schema: ({ image }) => + z.object({ + name: z.string().min(1), + description: z.string().optional(), + github: z.string().min(1).optional(), + image: image().optional(), + }), }) const tagsAboutSchema = z.object({ @@ -58,25 +48,15 @@ const tagsAboutSchema = z.object({ const tagsCollection = defineCollection({ type: 'data', - schema: z.object({ - name: z.string().min(1), - image: z - .discriminatedUnion('type', [ - z.object({ - type: z.literal('svg'), - name: z.string().min(1), - }), - z.object({ - type: z.literal('external-url'), - url: z.string().url(), - }), - ]) - .default({ type: 'svg', name: 'hashtag' }), - description: z.string().optional(), - site: tagsAboutSchema.optional(), - document: tagsAboutSchema.optional(), - github: tagsAboutSchema.optional(), - }), + schema: ({ image }) => + z.object({ + name: z.string().min(1), + description: z.string().optional(), + site: tagsAboutSchema.optional(), + document: tagsAboutSchema.optional(), + github: tagsAboutSchema.optional(), + image: image().optional(), + }), }) export const collections = { diff --git a/src/content/tags/arduino.json b/src/content/tags/arduino.json index 69da9fc..def4a72 100644 --- a/src/content/tags/arduino.json +++ b/src/content/tags/arduino.json @@ -1,7 +1,4 @@ { "name": "Arduino", - "image": { - "type": "svg", - "name": "arduino" - } + "image": "./arduino.svg" } diff --git a/src/assets/icons/blog/arduino.svg b/src/content/tags/arduino.svg similarity index 100% rename from src/assets/icons/blog/arduino.svg rename to src/content/tags/arduino.svg diff --git a/src/content/tags/astro.json b/src/content/tags/astro.json index 3c737c6..c526a1d 100644 --- a/src/content/tags/astro.json +++ b/src/content/tags/astro.json @@ -1,7 +1,4 @@ { "name": "Astro", - "image": { - "type": "svg", - "name": "astro-icon-dark" - } + "image": "./astro.svg" } diff --git a/src/assets/icons/blog/astro-icon-dark.svg b/src/content/tags/astro.svg similarity index 100% rename from src/assets/icons/blog/astro-icon-dark.svg rename to src/content/tags/astro.svg diff --git a/src/content/tags/csharp.json b/src/content/tags/csharp.json index 99b72a5..ede6730 100644 --- a/src/content/tags/csharp.json +++ b/src/content/tags/csharp.json @@ -1,10 +1,7 @@ { "name": "C#", - "image": { - "type": "svg", - "name": "csharp" - }, "description": "C#は、最新のタイプ セーフなオブジェクト指向のプログラミング言語です。 開発者は C# を使用することにより、.NET で稼働する、安全かつ堅牢な多くの種類のアプリケーションを構築できます。", + "image": "./csharp.svg", "site": { "url": "https://dotnet.microsoft.com/ja-jp/learn/dotnet/what-is-dotnet" }, diff --git a/src/assets/icons/blog/csharp.svg b/src/content/tags/csharp.svg similarity index 100% rename from src/assets/icons/blog/csharp.svg rename to src/content/tags/csharp.svg diff --git a/src/content/tags/discord-bot.json b/src/content/tags/discord-bot.json index e8a760c..46de62c 100644 --- a/src/content/tags/discord-bot.json +++ b/src/content/tags/discord-bot.json @@ -1,7 +1,4 @@ { "name": "Discord Bot", - "image": { - "type": "svg", - "name": "discord-mark-black" - } + "image": "./discord-bot.svg" } diff --git a/src/assets/icons/blog/discord-mark-black.svg b/src/content/tags/discord-bot.svg similarity index 100% rename from src/assets/icons/blog/discord-mark-black.svg rename to src/content/tags/discord-bot.svg diff --git a/src/content/tags/docker.json b/src/content/tags/docker.json index e9ec35e..55fb880 100644 --- a/src/content/tags/docker.json +++ b/src/content/tags/docker.json @@ -1,7 +1,4 @@ { "name": "Docker", - "image": { - "type": "svg", - "name": "docker" - } + "image": "./docker.svg" } diff --git a/src/assets/icons/blog/docker.svg b/src/content/tags/docker.svg similarity index 100% rename from src/assets/icons/blog/docker.svg rename to src/content/tags/docker.svg diff --git a/src/content/tags/dotnet.json b/src/content/tags/dotnet.json index b0b2cf2..400ec25 100644 --- a/src/content/tags/dotnet.json +++ b/src/content/tags/dotnet.json @@ -1,7 +1,4 @@ { "name": ".NET", - "image": { - "type": "svg", - "name": "dotnet-logo" - } + "image": "./dotnet.svg" } diff --git a/src/assets/icons/blog/dotnet-logo.svg b/src/content/tags/dotnet.svg similarity index 100% rename from src/assets/icons/blog/dotnet-logo.svg rename to src/content/tags/dotnet.svg diff --git a/src/content/tags/electronic-dictionary.json b/src/content/tags/electronic-dictionary.json index 1ff8327..38f5291 100644 --- a/src/content/tags/electronic-dictionary.json +++ b/src/content/tags/electronic-dictionary.json @@ -1,7 +1,4 @@ { "name": "電子辞書", - "image": { - "type": "svg", - "name": "laptop" - } + "image": "./electronic-dictionary.svg" } diff --git a/src/assets/icons/blog/laptop.svg b/src/content/tags/electronic-dictionary.svg similarity index 100% rename from src/assets/icons/blog/laptop.svg rename to src/content/tags/electronic-dictionary.svg diff --git a/src/content/tags/git.json b/src/content/tags/git.json index 79210da..fb3175e 100644 --- a/src/content/tags/git.json +++ b/src/content/tags/git.json @@ -1,7 +1,4 @@ { "name": "Git", - "image": { - "type": "svg", - "name": "git" - } + "image": "./git.svg" } diff --git a/src/assets/icons/blog/git.svg b/src/content/tags/git.svg similarity index 100% rename from src/assets/icons/blog/git.svg rename to src/content/tags/git.svg diff --git a/src/content/tags/go.json b/src/content/tags/go.json index a1d6826..8097d5d 100644 --- a/src/content/tags/go.json +++ b/src/content/tags/go.json @@ -1,9 +1,6 @@ { "name": "Go", - "image": { - "type": "svg", - "name": "Go-Logo_Aqua" - }, + "image": "./go.svg", "site": { "url": "https://go.dev/" }, diff --git a/src/assets/icons/blog/Go-Logo_Aqua.svg b/src/content/tags/go.svg similarity index 100% rename from src/assets/icons/blog/Go-Logo_Aqua.svg rename to src/content/tags/go.svg diff --git a/src/content/tags/markdown.json b/src/content/tags/markdown.json index e769213..596fe5a 100644 --- a/src/content/tags/markdown.json +++ b/src/content/tags/markdown.json @@ -1,7 +1,4 @@ { "name": "Markdown", - "image": { - "type": "svg", - "name": "Markdown-mark" - } + "image": "./markdown.svg" } diff --git a/src/assets/icons/blog/Markdown-mark.svg b/src/content/tags/markdown.svg similarity index 100% rename from src/assets/icons/blog/Markdown-mark.svg rename to src/content/tags/markdown.svg diff --git a/src/content/tags/python.json b/src/content/tags/python.json index 3ebe57c..ef6befe 100644 --- a/src/content/tags/python.json +++ b/src/content/tags/python.json @@ -1,10 +1,7 @@ { "name": "Python", "description": "Python はインタープリタ型の高水準汎用プログラミング言語です。", - "image": { - "type": "svg", - "name": "python-logo-only" - }, + "image": "./python.svg", "site": { "url": "https://www.python.org/", "text": "Python | Official Site" diff --git a/src/assets/icons/blog/python-logo-only.svg b/src/content/tags/python.svg similarity index 100% rename from src/assets/icons/blog/python-logo-only.svg rename to src/content/tags/python.svg diff --git a/src/content/tags/rest-api.json b/src/content/tags/rest-api.json index efbd26c..f97cb5e 100644 --- a/src/content/tags/rest-api.json +++ b/src/content/tags/rest-api.json @@ -1,7 +1,4 @@ { "name": "REST API", - "image": { - "type": "svg", - "name": "rest-api-icon" - } + "image": "./rest-api.svg" } diff --git a/src/assets/icons/blog/rest-api-icon.svg b/src/content/tags/rest-api.svg similarity index 100% rename from src/assets/icons/blog/rest-api-icon.svg rename to src/content/tags/rest-api.svg diff --git a/src/content/tags/rust.json b/src/content/tags/rust.json index f28af36..0eed2f4 100644 --- a/src/content/tags/rust.json +++ b/src/content/tags/rust.json @@ -1,7 +1,4 @@ { "name": "Rust", - "image": { - "type": "svg", - "name": "rust-logo-blk" - } + "image": "./rust.svg" } diff --git a/src/assets/icons/blog/rust-logo-blk.svg b/src/content/tags/rust.svg similarity index 100% rename from src/assets/icons/blog/rust-logo-blk.svg rename to src/content/tags/rust.svg diff --git a/src/content/tags/unity.json b/src/content/tags/unity.json index f4b8928..2f5f1e9 100644 --- a/src/content/tags/unity.json +++ b/src/content/tags/unity.json @@ -1,9 +1,6 @@ { "name": "Unity", - "image": { - "type": "svg", - "name": "U_ProfileIcon_Positive" - }, + "image": "./unity.svg", "site": { "url": "https://unity.com" } diff --git a/src/assets/icons/blog/U_ProfileIcon_Positive.svg b/src/content/tags/unity.svg similarity index 100% rename from src/assets/icons/blog/U_ProfileIcon_Positive.svg rename to src/content/tags/unity.svg diff --git a/src/pages/blog/authors/[slug]/index.astro b/src/pages/blog/authors/[slug]/index.astro index ef85058..21eebe4 100644 --- a/src/pages/blog/authors/[slug]/index.astro +++ b/src/pages/blog/authors/[slug]/index.astro @@ -1,10 +1,11 @@ --- +import defaultOgImage from '@/assets/avatar.svg' import BlogListSection from '@/components/blog/BlogListSection.astro' import BlogTitle from '@/components/blog/BlogTitle.astro' import AuthorAboutSection from '@/components/blog/author/AuthorAboutSection.astro' import AuthorIcon from '@/components/blog/icon/AuthorIcon.astro' import BlogLayout from '@/layouts/BlogLayout.astro' -import { unreachable } from '@/utils/unreachable' +import { getImageWithSvgConvert } from '@/utils/getImageWithSvgConvert' import { getCollection } from 'astro:content' export async function getStaticPaths() { const authorEntries = await getCollection('authors') @@ -16,16 +17,19 @@ export async function getStaticPaths() { const { author } = Astro.props const blogEntries = await getCollection('blogs') -const ogpPath = - author.data.image.type === 'svg' && - author.data.image.name === 'default_user' && - author.data.github - ? `https://github.com/${author.data.github}.png` - : author.data.image.type === 'svg' - ? `/authors/${author.id}/ogp.png` - : author.data.image.type === 'external-url' - ? author.data.image.url - : unreachable(author.data.image) +const ogpPath = await (async () => { + if (author.data.image !== undefined) { + return ( + await getImageWithSvgConvert({ src: author.data.image, format: 'jpeg' }) + ).src + } else if (author.data.github !== undefined) { + return `https://github.com/${author.data.github}.png` + } else { + return ( + await getImageWithSvgConvert({ src: defaultOgImage, format: 'jpeg' }) + ).src + } +})() const isShowAboutSection = author.data.description || author.data.github --- @@ -35,7 +39,7 @@ const isShowAboutSection = author.data.description || author.data.github description={author.data.description ?? `${author.data.name}さんのプロフィール`} image={ogpPath} - summarySize={ogpPath === undefined ? undefined : 'summary'} + summarySize="summary" > diff --git a/src/pages/blog/authors/[slug]/ogp.png.ts b/src/pages/blog/authors/[slug]/ogp.png.ts deleted file mode 100644 index fc951bc..0000000 --- a/src/pages/blog/authors/[slug]/ogp.png.ts +++ /dev/null @@ -1,38 +0,0 @@ -import type { APIContext } from 'astro' -import { getCollection } from 'astro:content' -import sharp from 'sharp' - -export async function getStaticPaths() { - const authors = await getCollection('authors') - - return authors - .filter( - (author) => - author.data.image.type !== 'svg' || - author.data.image.name !== 'default_user' || - !author.data.github, - ) - .map((author) => ({ - params: { slug: author.id }, - props: { author }, - })) -} - -export async function GET({ - props: { author }, -}: APIContext>[number]['props']>) { - if (author.data.image?.type !== 'svg') - return new Response(undefined, { status: 404 }) - const ogp = await sharp( - Buffer.from( - ( - await import( - `../../../../assets/icons/blog/${author.data.image.name}.svg?raw` - ) - ).default, - ), - ) - .png() - .toBuffer() - return new Response(ogp) -} diff --git a/src/pages/blog/tags/[slug]/index.astro b/src/pages/blog/tags/[slug]/index.astro index 83c20b9..b026acf 100644 --- a/src/pages/blog/tags/[slug]/index.astro +++ b/src/pages/blog/tags/[slug]/index.astro @@ -1,10 +1,11 @@ --- +import defaultOgImage from '@/assets/hashtag.svg' import BlogListSection from '@/components/blog/BlogListSection.astro' import BlogTitle from '@/components/blog/BlogTitle.astro' import TagIcon from '@/components/blog/icon/TagIcon.astro' import TagAboutSection from '@/components/blog/tag/TagAboutSection.astro' import BlogLayout from '@/layouts/BlogLayout.astro' -import { unreachable } from '@/utils/unreachable' +import { getImageWithSvgConvert } from '@/utils/getImageWithSvgConvert' import { getCollection } from 'astro:content' export async function getStaticPaths() { const tagEntries = await getCollection('tags') @@ -19,17 +20,20 @@ const { } = Astro.props const blogEntries = await getCollection('blogs') +const ogpPath = ( + await getImageWithSvgConvert({ + src: tag.image ?? defaultOgImage, + format: 'jpeg', + }) +).src + const isShowAbout = tag.description || tag.site || tag.document || tag.github --- diff --git a/src/pages/blog/tags/[slug]/ogp.png.ts b/src/pages/blog/tags/[slug]/ogp.png.ts deleted file mode 100644 index 9dce848..0000000 --- a/src/pages/blog/tags/[slug]/ogp.png.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { APIContext } from 'astro' -import { getCollection } from 'astro:content' -import sharp from 'sharp' - -export async function getStaticPaths() { - const tags = await getCollection('tags') - - return tags - .filter((tag) => tag.data.image.type === 'svg') - .map((tag) => ({ - params: { slug: tag.id }, - props: { tag }, - })) -} - -export async function GET({ - props: { tag }, -}: APIContext>[number]['props']>) { - if (tag.data.image.type !== 'svg') - return new Response(undefined, { status: 404 }) - const ogp = await sharp( - Buffer.from( - ( - await import( - `../../../../assets/icons/blog/${tag.data.image.name}.svg?raw` - ) - ).default, - ), - ) - .png() - .toBuffer() - return new Response(ogp) -} diff --git a/src/utils/getImageWithSvgConvert.ts b/src/utils/getImageWithSvgConvert.ts new file mode 100644 index 0000000..cd57970 --- /dev/null +++ b/src/utils/getImageWithSvgConvert.ts @@ -0,0 +1,29 @@ +import type { ImageTransform } from 'astro' +import { getImage } from 'astro:assets' + +/** + * `astro:assets`の`getImage`を拡張し、SVGからラスター画像への変換を可能にしたもの。 + * + * `getImage`は入力にSVGを与えたとき、オプションでの出力フォーマット指定を無視し必ずSVGを返してしまう。 + * これではOGP画像生成の際にSVGからPNGへの変換ができず困るので、この関数では出力フォーマットを無視しないよう修正した。 + */ +export const getImageWithSvgConvert = async ( + options: Omit & { + src: ImageMetadata | Promise<{ default: ImageMetadata }> + }, +) => { + // `src`がPromiseである場合、そのPromiseが解決されるまで待機する。 + const src = + typeof options.src === 'object' && 'then' in options.src + ? (await options.src).default ?? (await options.src) + : options.src + + // 入力画像がSVGかつ出力フォーマット指定がSVG以外のとき + if (src.format === 'svg' && options.format !== 'svg') { + // 入力画像がPNGであるかのようにAstroを騙し、ラスター画像への変換を可能にする。 + // 具体的には次のチェックを回避している:https://github.com/withastro/astro/blob/895ebcb5bfeb2fe08ae939eaceeb0405cff91ca5/packages/astro/src/assets/services/service.ts#L199-L202 + return await getImage({ ...options, src: { ...src, format: 'png' } }) + } else { + return await getImage(options) + } +} From d40c72b8d1d68efd8b2673b45adc69b7b3aec3e3 Mon Sep 17 00:00:00 2001 From: Ciffelia Date: Fri, 8 Dec 2023 00:15:48 +0900 Subject: [PATCH 3/3] =?UTF-8?q?=E4=B8=80=E9=83=A8=E3=81=AEOGP=E7=94=BB?= =?UTF-8?q?=E5=83=8F=E3=81=AFPNG=E3=81=A7=E5=87=BA=E5=8A=9B=E3=81=99?= =?UTF-8?q?=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/blog/authors/[slug]/index.astro | 2 +- src/pages/blog/tags/[slug]/index.astro | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/blog/authors/[slug]/index.astro b/src/pages/blog/authors/[slug]/index.astro index 21eebe4..6b9830b 100644 --- a/src/pages/blog/authors/[slug]/index.astro +++ b/src/pages/blog/authors/[slug]/index.astro @@ -26,7 +26,7 @@ const ogpPath = await (async () => { return `https://github.com/${author.data.github}.png` } else { return ( - await getImageWithSvgConvert({ src: defaultOgImage, format: 'jpeg' }) + await getImageWithSvgConvert({ src: defaultOgImage, format: 'png' }) ).src } })() diff --git a/src/pages/blog/tags/[slug]/index.astro b/src/pages/blog/tags/[slug]/index.astro index abefaf8..0a855af 100644 --- a/src/pages/blog/tags/[slug]/index.astro +++ b/src/pages/blog/tags/[slug]/index.astro @@ -23,7 +23,7 @@ const blogEntries = await getCollection('blogs') const ogpPath = ( await getImageWithSvgConvert({ src: tag.image ?? defaultOgImage, - format: 'jpeg', + format: 'png', }) ).src