diff --git a/src/components/PhotoGallery/index.ts b/src/components/ui/PhotoGallery/index.ts
similarity index 100%
rename from src/components/PhotoGallery/index.ts
rename to src/components/ui/PhotoGallery/index.ts
diff --git a/src/components/ProfileIcon/ProfileIcon.astro b/src/components/ui/ProfileIcon/ProfileIcon.astro
similarity index 95%
rename from src/components/ProfileIcon/ProfileIcon.astro
rename to src/components/ui/ProfileIcon/ProfileIcon.astro
index 9df75bb3..6fbbe9ca 100644
--- a/src/components/ProfileIcon/ProfileIcon.astro
+++ b/src/components/ui/ProfileIcon/ProfileIcon.astro
@@ -30,8 +30,6 @@ const { src, size, alt, class: className, ...rest } = Astro.props;
width={size}
height={size}
loading="eager"
- format="avif"
- quality={75}
/>
)
}
diff --git a/src/components/ProfileIcon/index.ts b/src/components/ui/ProfileIcon/index.ts
similarity index 100%
rename from src/components/ProfileIcon/index.ts
rename to src/components/ui/ProfileIcon/index.ts
diff --git a/src/components/StarRating/StarIcon.tsx b/src/components/ui/StarRating/StarIcon.tsx
similarity index 100%
rename from src/components/StarRating/StarIcon.tsx
rename to src/components/ui/StarRating/StarIcon.tsx
diff --git a/src/components/StarRating/StarRating.astro b/src/components/ui/StarRating/StarRating.astro
similarity index 98%
rename from src/components/StarRating/StarRating.astro
rename to src/components/ui/StarRating/StarRating.astro
index 0b0f9a36..12959572 100644
--- a/src/components/StarRating/StarRating.astro
+++ b/src/components/ui/StarRating/StarRating.astro
@@ -1,6 +1,6 @@
---
import { getEntry } from 'astro:content';
-import { Icon } from '@/components/Icon';
+import { Icon } from '@/components/ui/Icon';
import { getLocaleFromUrl } from '@/utils/i18n/utils';
import { StarIcon } from './StarIcon';
import {
diff --git a/src/components/StarRating/index.ts b/src/components/ui/StarRating/index.ts
similarity index 100%
rename from src/components/StarRating/index.ts
rename to src/components/ui/StarRating/index.ts
diff --git a/src/components/StarRating/star-rating.css.ts b/src/components/ui/StarRating/star-rating.css.ts
similarity index 100%
rename from src/components/StarRating/star-rating.css.ts
rename to src/components/ui/StarRating/star-rating.css.ts
diff --git a/src/components/Toaster/Toaster.tsx b/src/components/ui/Toaster/Toaster.tsx
similarity index 100%
rename from src/components/Toaster/Toaster.tsx
rename to src/components/ui/Toaster/Toaster.tsx
diff --git a/src/content/blog/en/astro-website.mdx b/src/content/blog/en/astro-website.mdx
index ede6331b..1a8d318f 100644
--- a/src/content/blog/en/astro-website.mdx
+++ b/src/content/blog/en/astro-website.mdx
@@ -2,7 +2,7 @@
title: Build a Personal Website with Astro, Cloudflare Pages, D1, and Front Matter CMS
description: A quick tour of my personal blog built with Astro, Cloudflare Pages, D1, and Front Matter CMS.
publishedAt: 2024-07-13T00:34:54.000Z
-modifiedAt: 2024-10-17T03:25:25.106Z
+modifiedAt: 2024-10-18T03:01:11.379Z
draft: published
type: blog
category:
@@ -16,6 +16,7 @@ tags:
- front-matter-cms
- cloudflare
level: 4
+image: /src/assets/images/younagidev.jpg
---
## Intro
diff --git a/src/content/blog/en/obsidian-knowledge-base.mdx b/src/content/blog/en/obsidian-knowledge-base.mdx
index 0d09c9e4..cb044005 100644
--- a/src/content/blog/en/obsidian-knowledge-base.mdx
+++ b/src/content/blog/en/obsidian-knowledge-base.mdx
@@ -5,7 +5,7 @@ type: blog
title: Create an Obsidian starter kit for knowledge base "NPKB"
publishedAt: 2024-09-05T04:11:06.403Z
fmContentType: blog
-modifiedAt: 2024-10-17T03:40:24.484Z
+modifiedAt: 2024-10-18T02:59:24.689Z
category:
metadata: en/categories
slug: learning
@@ -15,6 +15,7 @@ tags:
- obsidian
- javascript
description: Building one's own knowledge base on Obsidian is a daunting task. Here, you'll learn about my starter kit and the notable points like the Evergreen Note ethos.
+image: /src/assets/images/npkb.png
---
## Intro
diff --git a/src/content/blog/en/total-newbie-builds-mini-itx-linux-pc.mdx b/src/content/blog/en/total-newbie-builds-mini-itx-linux-pc.mdx
index f68d20ce..49262925 100644
--- a/src/content/blog/en/total-newbie-builds-mini-itx-linux-pc.mdx
+++ b/src/content/blog/en/total-newbie-builds-mini-itx-linux-pc.mdx
@@ -5,7 +5,7 @@ type: blog
title: Total newbie builds Mini-ITX Linux PC (Error after Error)
publishedAt: 2024-09-19T01:48:09.453Z
fmContentType: blog
-modifiedAt: 2024-10-17T06:04:02.128Z
+modifiedAt: 2024-10-18T02:03:19.205Z
category:
metadata: en/categories
slug: learning
@@ -16,6 +16,7 @@ tags:
- pc
- nixos
description: A newbie builds Mini-ITC PC. You'll learn some tricky points explained from the beginner's standpoint from parts selection to OS installation.
+image: /src/assets/images/pc-parts.webp
---
## Intro
diff --git a/src/content/blog/ja/astro-website.mdx b/src/content/blog/ja/astro-website.mdx
index df50a14f..8b4c98e9 100644
--- a/src/content/blog/ja/astro-website.mdx
+++ b/src/content/blog/ja/astro-website.mdx
@@ -2,7 +2,7 @@
title: Astro + Cloudflare Pages + D1 + Front Matter CMS で個人ウェブサイトを作った
description: Astro + Cloudflare Pages + D1 + Front Matter CMSの構成で作った個人ウェブサイトの開発体験を簡単に紹介する
publishedAt: 2024-07-13T00:35:10.000Z
-modifiedAt: 2024-10-17T03:16:06.824Z
+modifiedAt: 2024-10-18T03:01:21.608Z
draft: published
type: blog
category:
@@ -16,6 +16,7 @@ tags:
- front-matter-cms
- cloudflare
level: 4
+image: /src/assets/images/younagidev.jpg
---
## 導入
diff --git a/src/content/blog/ja/obsidian-knowledge-base.mdx b/src/content/blog/ja/obsidian-knowledge-base.mdx
index 3c390166..0cbff7e3 100644
--- a/src/content/blog/ja/obsidian-knowledge-base.mdx
+++ b/src/content/blog/ja/obsidian-knowledge-base.mdx
@@ -5,7 +5,7 @@ type: blog
title: Obsidian でナレッジベース用のスターターキット「NPKB」を作った
publishedAt: 2024-09-05T04:10:55.070Z
fmContentType: blog
-modifiedAt: 2024-10-17T04:34:47.012Z
+modifiedAt: 2024-10-18T02:59:31.860Z
category:
metadata: ja/categories
slug: learning
@@ -15,6 +15,7 @@ tags:
- obsidian
- javascript
description: Obsidian でナレッジベースを築き上げるのは骨が折れるタスクだ。本記事では、私が作った専用スターターキットについて、エバーグリーンノートなど重要な点にふれつつ紹介する。
+image: /src/assets/images/npkb.png
---
## 導入
diff --git a/src/content/blog/ja/total-newbie-builds-mini-itx-linux-pc.mdx b/src/content/blog/ja/total-newbie-builds-mini-itx-linux-pc.mdx
index 3ddd8bbd..0d2a0f86 100644
--- a/src/content/blog/ja/total-newbie-builds-mini-itx-linux-pc.mdx
+++ b/src/content/blog/ja/total-newbie-builds-mini-itx-linux-pc.mdx
@@ -5,7 +5,7 @@ type: blog
title: 【エラーだらけ】PC 自作初心者が Mini-ITX の Linux PC を組み立てる
publishedAt: 2024-09-19T01:48:03.469Z
fmContentType: blog
-modifiedAt: 2024-10-17T06:30:08.908Z
+modifiedAt: 2024-10-18T02:03:23.998Z
category:
metadata: ja/categories
slug: learning
@@ -16,6 +16,7 @@ tags:
- pc
- nixos
description: PC 自作初心者が Mini-ITX PC を作った記録。パーツ選定からOSインストールまで、初心者目線でつまずいたポイントも解説する。
+image: /src/assets/images/pc-parts.webp
---
## 導入
diff --git a/src/content/config.ts b/src/content/config.ts
index d6a616f7..5128a92d 100644
--- a/src/content/config.ts
+++ b/src/content/config.ts
@@ -3,7 +3,7 @@ import {
type TaxonomyColor,
type TaxonomyColorEnum,
taxonomyColors,
-} from '@/components/Taxonomy';
+} from '@/components/models/Taxonomy';
const blog = defineCollection({
type: 'content',
@@ -30,6 +30,7 @@ const blog = defineCollection({
z.literal(5),
])
.optional(),
+ image: z.string().optional(),
}),
});
diff --git a/src/content/page/en/tools.mdx b/src/content/page/en/tools.mdx
index 8c405550..a9b880f7 100644
--- a/src/content/page/en/tools.mdx
+++ b/src/content/page/en/tools.mdx
@@ -1,7 +1,7 @@
---
title: Tools I Use
fmContentType: page
-modifiedAt: 2024-09-19T05:53:34.076Z
+modifiedAt: 2024-10-18T02:55:05.998Z
description: Here are software & hardware tools I use daily.
---
@@ -128,6 +128,10 @@ It's mainly used for coding. (Built in Aug 2024)
- [![audio-technica ATH-R70x](../../../assets/images/audio-technica-ath-r70x.webp)](https://www.audio-technica.co.jp/product/ATH-R70x?srsltid=AfmBOorXxQEzMYddDoDzfjSaT2bvyxwxa9GGJ8_6uAUcM46nGRhKQLoV)
- **audio-technica ATH-R70x**
- Open-ear Headphones
+- @= IK Multimedia iLoud MTM MKII
+ - [![IK Multimedia iLoud MTM MKII](../../../assets/images/ik-multimedia-iloud-mtm-mkii.avif)](https://hookup.co.jp/products/ik-multimedia/iloud-mtm-mkii)
+ - **IK Multimedia iLoud MTM MKII**
+ - Monitor Speaker Pair
- @= Native Instruments KONTROL S49 MK3
- [![Native Instruments KONTROL S49 MK3](../../../assets/images/ni-kontrol-s49-mk3.avif)](https://www.native-instruments.com/en/products/komplete/keyboards/kontrol-s49-s61-s88/?srsltid=AfmBOoolwxp027K1WdrXT-F6aNQZvotWgM7xyyO05yT1SqKyw491uFz9)
- **Native Instruments KONTROL S49 MK3**
@@ -160,14 +164,6 @@ It's mainly used for coding. (Built in Aug 2024)
- [![SIGMA 18-50mm F2.8 DC DN Contemporary SONY E-mount](../../../assets/images/sigma-dc-dn-contemporary-e-mount.webp)](https://www.sigma-global.com/jp/lenses/c021_18_50_28/)
- **SIGMA 18-50mm F2.8 DC DN Contemporary SONY E-mount**
- Lens
-- @= TASCAM Portacapture X8
- - [![TASCAM Portacapture X8](../../../assets/images/tascam-portacapture-x8.webp)](https://tascam.jp/us/product/portacapture_x8/top)
- - **TASCAM Portacapture X8**
- - 32bit float Linear PCM Recorder
-- @= TASCAM DR-10L Pro
- - [![TASCAM DR-10L Pro](../../../assets/images/tascam-dr-10l-pro.webp)](https://tascam.jp/us/product/dr-10l_pro/top)
- - **TASCAM DR-10L Pro**
- - Lavalier Microphone & Field Recorder
---
- @= DaVinci Resolve
- [![ DaVinci Resolve ](../../../assets/images/davinci-resolve-icon.webp)](https://www.blackmagicdesign.com/products/davinciresolve)
@@ -177,3 +173,14 @@ It's mainly used for coding. (Built in Aug 2024)
- [![ SONY Creator's App ](../../../assets/images/sony-creators-app-icon.webp)](https://creatorscloud.sony.net/catalog/en-us/creatorsapp/index.html)
- **SONY Creator's App**
- Media Data Transferring among Devices
+
+### Field Recording
+
+- @= TASCAM Portacapture X8
+ - [![TASCAM Portacapture X8](../../../assets/images/tascam-portacapture-x8.webp)](https://tascam.jp/us/product/portacapture_x8/top)
+ - **TASCAM Portacapture X8**
+ - 32bit float Linear PCM Recorder
+- @= TASCAM DR-10L Pro
+ - [![TASCAM DR-10L Pro](../../../assets/images/tascam-dr-10l-pro.webp)](https://tascam.jp/us/product/dr-10l_pro/top)
+ - **TASCAM DR-10L Pro**
+ - Lavalier Microphone & Field Recorder
diff --git a/src/content/page/ja/tools.mdx b/src/content/page/ja/tools.mdx
index b1a74a1a..e990bf24 100644
--- a/src/content/page/ja/tools.mdx
+++ b/src/content/page/ja/tools.mdx
@@ -1,7 +1,7 @@
---
title: 愛用ツール群
fmContentType: page
-modifiedAt: 2024-09-19T05:53:45.155Z
+modifiedAt: 2024-10-18T02:54:39.329Z
description: 私が普段使っているソフトウェア&ハードウェア群
---
@@ -128,6 +128,10 @@ description: 私が普段使っているソフトウェア&ハードウェア群
- [![audio-technica ATH-R70x](../../../assets/images/audio-technica-ath-r70x.webp)](https://www.audio-technica.co.jp/product/ATH-R70x?srsltid=AfmBOorXxQEzMYddDoDzfjSaT2bvyxwxa9GGJ8_6uAUcM46nGRhKQLoV)
- **audio-technica ATH-R70x**
- 開放型ヘッドホン
+- @= IK Multimedia iLoud MTM MKII
+ - [![IK Multimedia iLoud MTM MKII](../../../assets/images/ik-multimedia-iloud-mtm-mkii.avif)](https://hookup.co.jp/products/ik-multimedia/iloud-mtm-mkii)
+ - **IK Multimedia iLoud MTM MKII**
+ - モニタースピーカーペア
- @= Native Instruments KONTROL S49 MK3
- [![Native Instruments KONTROL S49 MK3](../../../assets/images/ni-kontrol-s49-mk3.avif)](https://www.native-instruments.com/jp/products/komplete/keyboards/kontrol-s49-s61-s88/?srsltid=AfmBOorn6uQIXlI_YanmNHKSwWa9FbmDOrIySmQBX-PuKlxS-4nnjPPs)
- **Native Instruments KONTROL S49 MK3**
@@ -160,14 +164,6 @@ description: 私が普段使っているソフトウェア&ハードウェア群
- [![SIGMA 18-50mm F2.8 DC DN Contemporary SONY E-mount](../../../assets/images/sigma-dc-dn-contemporary-e-mount.webp)](https://www.sigma-global.com/jp/lenses/c021_18_50_28/)
- **SIGMA 18-50mm F2.8 DC DN Contemporary SONY E-mount**
- レンズ
-- @= TASCAM Portacapture X8
- - [![TASCAM Portacapture X8](../../../assets/images/tascam-portacapture-x8.webp)](https://tascam.jp/us/product/portacapture_x8/top)
- - **TASCAM Portacapture X8**
- - 32 ビットフロートリニア PCM レコーダー
-- @= TASCAM DR-10L Pro
- - [![TASCAM DR-10L Pro](../../../assets/images/tascam-dr-10l-pro.webp)](https://tascam.jp/us/product/dr-10l_pro/top)
- - **TASCAM DR-10L Pro**
- - ラべリアマイク&フィールドレコーダー
---
- @= DaVinci Resolve
- [![ DaVinci Resolve ](../../../assets/images/davinci-resolve-icon.webp)](https://www.blackmagicdesign.com/products/davinciresolve)
@@ -177,3 +173,14 @@ description: 私が普段使っているソフトウェア&ハードウェア群
- [![ SONY Creator's App ](../../../assets/images/sony-creators-app-icon.webp)](https://creatorscloud.sony.net/catalog/ja-jp/creatorsapp/index.html)
- **SONY Creator's App**
- メディアデータのデバイス間連携
+
+### フィールドレコーディング
+
+- @= TASCAM Portacapture X8
+ - [![TASCAM Portacapture X8](../../../assets/images/tascam-portacapture-x8.webp)](https://tascam.jp/us/product/portacapture_x8/top)
+ - **TASCAM Portacapture X8**
+ - 32 ビットフロートリニア PCM レコーダー
+- @= TASCAM DR-10L Pro
+ - [![TASCAM DR-10L Pro](../../../assets/images/tascam-dr-10l-pro.webp)](https://tascam.jp/us/product/dr-10l_pro/top)
+ - **TASCAM DR-10L Pro**
+ - ラべリアマイク&フィールドレコーダー
diff --git a/src/layouts/AboutLayout.astro b/src/layouts/AboutLayout.astro
index 6bface7f..d8823e6d 100644
--- a/src/layouts/AboutLayout.astro
+++ b/src/layouts/AboutLayout.astro
@@ -1,12 +1,12 @@
---
import { getEntry } from 'astro:content';
import ProfileImage from '@/assets/images/profile.png';
-import { Article } from '@/components/Article';
-import { ContactForm } from '@/components/ContactForm/ContactForm';
-import { Icon } from '@/components/Icon';
-import { Modal } from '@/components/Modal/Modal';
-import { ProfileIcon } from '@/components/ProfileIcon';
-import { Toc } from '@/components/Toc';
+import { Article } from '@/components/models/Article';
+import { Toc } from '@/components/models/Toc';
+import { ContactForm } from '@/components/ui/ContactForm/ContactForm';
+import { Icon } from '@/components/ui/Icon';
+import { Modal } from '@/components/ui/Modal/Modal';
+import { ProfileIcon } from '@/components/ui/ProfileIcon';
import BaseLayout from '@/layouts/BaseLayout.astro';
import { transparentButton } from '@/styles/styles.css';
import { getLocaleFromUrl } from '@/utils/i18n/utils';
diff --git a/src/layouts/BaseLayout.astro b/src/layouts/BaseLayout.astro
index ba96c717..2d07e2e6 100644
--- a/src/layouts/BaseLayout.astro
+++ b/src/layouts/BaseLayout.astro
@@ -1,10 +1,10 @@
---
-import { BaseHead } from '@/components/BaseHead';
-import { Footer } from '@/components/Footer';
-import { LocaleStore } from '@/components/LocaleStore/LocaleStore';
-import { Navigation } from '@/components/Navigation';
-import { Toaster } from '@/components/Toaster/Toaster';
-import { UrlStore } from '@/components/UrlStore/UrlStore';
+import { BaseHead } from '@/components/common/BaseHead';
+import { Footer } from '@/components/common/Footer';
+import { Navigation } from '@/components/common/Navigation';
+import { LocaleStore } from '@/components/functional/LocaleStore/LocaleStore';
+import { UrlStore } from '@/components/functional/UrlStore/UrlStore';
+import { Toaster } from '@/components/ui/Toaster/Toaster';
import { getLocaleFromUrl } from '@/utils/i18n/utils';
export type Props = {
diff --git a/src/layouts/BlogLayout.astro b/src/layouts/BlogLayout.astro
index 5321221e..c5591bee 100644
--- a/src/layouts/BlogLayout.astro
+++ b/src/layouts/BlogLayout.astro
@@ -2,18 +2,19 @@
import 'katex/dist/katex.min.css';
import type { CollectionEntry } from 'astro:content';
import { getEntry } from 'astro:content';
-import { Article } from '@/components/Article';
-import { BuyMeACoffee } from '@/components/BuyMeACoffee';
-import { FormattedDate } from '@/components/FormattedDate';
-import { Icon } from '@/components/Icon';
-import { Likes } from '@/components/Likes/Likes';
-import { StarRating } from '@/components/StarRating';
-import { Taxonomy } from '@/components/Taxonomy';
-import { Toc } from '@/components/Toc';
+import { Article } from '@/components/models/Article';
+import { FormattedDate } from '@/components/models/FormattedDate';
+import { Taxonomy } from '@/components/models/Taxonomy';
+import { Toc } from '@/components/models/Toc';
+import { BuyMeACoffee } from '@/components/ui/BuyMeACoffee';
+import { Icon } from '@/components/ui/Icon';
+import { Likes } from '@/components/ui/Likes/Likes';
+import { StarRating } from '@/components/ui/StarRating';
import BaseLayout from '@/layouts/BaseLayout.astro';
import { getBlogCategory, getBlogTags } from '@/lib/collections/data';
import { getSlugWithoutLocale } from '@/utils/get-slug-without-locale';
import { getLocaleFromUrl, useTranslatedPath } from '@/utils/i18n/utils';
+// import { Image } from 'astro:assets';
import type { MarkdownHeading } from 'astro';
type Props = {
@@ -34,6 +35,7 @@ const {
publishedAt,
modifiedAt,
level,
+ // image,
} = data;
const slugWithoutLocale = getSlugWithoutLocale(slug);
const category = await getBlogCategory(blogCategory);
@@ -71,6 +73,16 @@ const tags = await getBlogTags(blogTags);
)
}
+
{title}
{
@@ -145,6 +157,10 @@ const tags = await getBlogTags(blogTags);
font-size: 1.125rem;
}
}
+ .hero-image {
+ border-radius: 0.375rem;
+ margin: 0.625rem 0;
+ }
.entry-title {
text-align: center;
font-size: 1.825rem;
diff --git a/src/layouts/NewsLayout.astro b/src/layouts/NewsLayout.astro
index d9b5fc7b..adb9e007 100644
--- a/src/layouts/NewsLayout.astro
+++ b/src/layouts/NewsLayout.astro
@@ -1,9 +1,9 @@
---
import type { CollectionEntry } from 'astro:content';
-import { Article } from '@/components/Article';
-import { BuyMeACoffee } from '@/components/BuyMeACoffee';
-import { FormattedDate } from '@/components/FormattedDate';
-import { Icon } from '@/components/Icon';
+import { Article } from '@/components/models/Article';
+import { FormattedDate } from '@/components/models/FormattedDate';
+import { BuyMeACoffee } from '@/components/ui/BuyMeACoffee';
+import { Icon } from '@/components/ui/Icon';
import BaseLayout from '@/layouts/BaseLayout.astro';
import { getSlugWithoutLocale } from '@/utils/get-slug-without-locale';
import { getLocaleFromUrl, useTranslatedPath } from '@/utils/i18n/utils';
diff --git a/src/layouts/PageLayout.astro b/src/layouts/PageLayout.astro
index 4c9ed7c3..e6852d14 100644
--- a/src/layouts/PageLayout.astro
+++ b/src/layouts/PageLayout.astro
@@ -1,8 +1,8 @@
---
import type { CollectionEntry } from 'astro:content';
-import { Article } from '@/components/Article';
-import { FormattedDate } from '@/components/FormattedDate';
-import { Icon } from '@/components/Icon';
+import { Article } from '@/components/models/Article';
+import { FormattedDate } from '@/components/models/FormattedDate';
+import { Icon } from '@/components/ui/Icon';
import BaseLayout from '@/layouts/BaseLayout.astro';
import { getLocaleFromUrl } from '@/utils/i18n/utils';
diff --git a/src/lib/astro-integrations/icon-name-type.ts b/src/lib/astro-integrations/icon-name-type.ts
index a995961c..9ebc10de 100644
--- a/src/lib/astro-integrations/icon-name-type.ts
+++ b/src/lib/astro-integrations/icon-name-type.ts
@@ -3,8 +3,8 @@ import { resolve } from 'node:path';
import type { AstroIntegration, AstroIntegrationLogger } from 'astro';
const generateIconNameType = async () => {
- const ICONS_DIR = '../../components/Icon/icons';
- const ICON_TYPES_DIR = '../../components/Icon/types.ts';
+ const ICONS_DIR = '../../components/ui/Icon/icons';
+ const ICON_TYPES_DIR = '../../components/ui/Icon/types.ts';
const iconsDir = resolve(import.meta.dirname, ICONS_DIR);
const iconFiles = await readdir(iconsDir);
diff --git a/src/lib/blur.ts b/src/lib/blur.ts
new file mode 100644
index 00000000..e8699a1c
--- /dev/null
+++ b/src/lib/blur.ts
@@ -0,0 +1,18 @@
+import sharp from 'sharp';
+
+export const getBlur = async (
+ buffer: Buffer,
+ size: number,
+ format: keyof sharp.FormatEnum,
+) => {
+ return await sharp(buffer)
+ .resize(size, size, { fit: 'inside' })
+ .toFormat(format, { quality: 60 })
+ .modulate({
+ brightness: 1,
+ saturation: 1.2,
+ })
+ .normalize()
+ .toBuffer()
+ .then((data) => `data:image/${format};base64,${data.toString('base64')}`);
+};
diff --git a/src/lib/images.ts b/src/lib/images.ts
new file mode 100644
index 00000000..846b8da2
--- /dev/null
+++ b/src/lib/images.ts
@@ -0,0 +1,39 @@
+const load = async () => {
+ let images: Record Promise> | undefined = undefined;
+
+ try {
+ images = import.meta.glob(
+ '@/assets/images/**/*.{jpeg,jpg,png,tiff,webp,gif,svg,JPEG,JPG,PNG,TIFF,WEBP,GIF,SVG}',
+ );
+ } catch (err) {
+ // continue anyhow
+ }
+
+ return images;
+};
+
+let _images: Record Promise> | undefined = undefined;
+
+export const fetchLocalImages = async () => {
+ _images = _images ?? (await load());
+
+ return _images;
+};
+
+export const findImage = async (
+ imagePath?: string | ImageMetadata | null,
+): Promise => {
+ if (typeof imagePath !== 'string') return imagePath;
+
+ if (imagePath.startsWith('http')) return imagePath;
+
+ if (!imagePath.startsWith('~/assets/images') || imagePath.startsWith('/'))
+ return imagePath;
+
+ const images = await fetchLocalImages();
+ const key = imagePath.replace('@/', '/src/');
+
+ return images && typeof images[key] === 'function'
+ ? ((await images[key]()) as { default: ImageMetadata }).default
+ : null;
+};
diff --git a/src/lib/mdx-components.ts b/src/lib/mdx-components.ts
index 85d35d43..a3662cdc 100644
--- a/src/lib/mdx-components.ts
+++ b/src/lib/mdx-components.ts
@@ -1,11 +1,11 @@
-import { Balloon } from '@/components/Balloon';
-import { Card, CardGrid } from '@/components/Card';
-import { FormattedDate } from '@/components/FormattedDate';
-import { StarRating } from '@/components/StarRating';
import { Callout, CalloutTitle } from '@/components/elements/Callout';
-import { Figure } from '@/components/elements/Figure';
+import { Card, CardGrid } from '@/components/elements/Card';
+import { Figure, Image } from '@/components/elements/Figure';
import { Link } from '@/components/elements/Link';
import { OEmbed } from '@/components/elements/OEmbed';
+import { FormattedDate } from '@/components/models/FormattedDate';
+import { Balloon } from '@/components/ui/Balloon';
+import { StarRating } from '@/components/ui/StarRating';
export const mdxComponents = {
a: Link,
@@ -16,6 +16,7 @@ export const mdxComponents = {
'card-grid': CardGrid,
figure: Figure,
FormattedDate,
+ img: Image,
oembed: OEmbed,
StarRating,
};
diff --git a/src/plugins/mdast-is.ts b/src/lib/unified/mdast-is.ts
similarity index 100%
rename from src/plugins/mdast-is.ts
rename to src/lib/unified/mdast-is.ts
diff --git a/src/plugins/rehype-pagefind-ignore.ts b/src/lib/unified/plugins/rehype-pagefind-ignore.ts
similarity index 100%
rename from src/plugins/rehype-pagefind-ignore.ts
rename to src/lib/unified/plugins/rehype-pagefind-ignore.ts
diff --git a/src/lib/unified/plugins/remark-astro-image-assets.ts b/src/lib/unified/plugins/remark-astro-image-assets.ts
new file mode 100644
index 00000000..bf6931c2
--- /dev/null
+++ b/src/lib/unified/plugins/remark-astro-image-assets.ts
@@ -0,0 +1,66 @@
+import fs from 'node:fs';
+import path from 'node:path';
+import type { RemarkPlugin } from '@astrojs/markdown-remark';
+import type { Image, Root } from 'mdast';
+import type { FormatEnum } from 'sharp';
+import type { Plugin } from 'unified';
+import { visit } from 'unist-util-visit';
+import { getBlur } from '../../blur';
+import { isLink, isParagraph } from '../mdast-is';
+
+type RemarkAstroImageAssetsOptions = {
+ imgDir: string;
+ size: number;
+ format: keyof FormatEnum;
+};
+
+const defaultRemarkAstroImageAssetsOptions: Readonly =
+ {
+ imgDir: './assets/images',
+ size: 8,
+ format: 'webp',
+ };
+
+const remarkAstroImageAssets: Plugin<[RemarkAstroImageAssetsOptions?], Root> = (
+ options = defaultRemarkAstroImageAssetsOptions,
+): ReturnType => {
+ return async (tree) => {
+ const imgs: Image[] = [];
+
+ visit(tree, 'image', (node, _i, parent) => {
+ if (
+ (!isParagraph(parent) && !isLink(parent)) ||
+ node.url.startsWith('http')
+ )
+ return;
+
+ imgs.push(node);
+ });
+
+ const { imgDir, size, format } = options;
+
+ await Promise.all(
+ imgs.map(async (node) => {
+ const basename = path.basename(node.url);
+ // const buffer = await Bun.file(
+ // path.join(process.cwd(), './src', imgDir, basename),
+ // ).arrayBuffer();
+ const buffer = fs.readFileSync(
+ path.join(process.cwd(), './src', imgDir, basename),
+ );
+
+ const base64 = await getBlur(buffer, size, format);
+
+ node.data = {
+ ...node.data,
+ hProperties: {
+ ...(node.data?.hProperties ?? {}),
+ placeholder: base64,
+ },
+ };
+ }),
+ );
+ };
+};
+
+export default remarkAstroImageAssets;
diff --git a/src/plugins/remark-callout.ts b/src/lib/unified/plugins/remark-callout.ts
similarity index 98%
rename from src/plugins/remark-callout.ts
rename to src/lib/unified/plugins/remark-callout.ts
index 78843177..513b0fe2 100644
--- a/src/plugins/remark-callout.ts
+++ b/src/lib/unified/plugins/remark-callout.ts
@@ -2,7 +2,7 @@ import type { RemarkPlugin } from '@astrojs/markdown-remark';
import type { BlockContent, DefinitionContent, Paragraph, Root } from 'mdast';
import type { Plugin } from 'unified';
import { visit } from 'unist-util-visit';
-import { isParagraph, isParent, isText } from './mdast-is';
+import { isParagraph, isParent, isText } from '../mdast-is';
type Callout = {
type: string;
diff --git a/src/plugins/remark-card.ts b/src/lib/unified/plugins/remark-card.ts
similarity index 73%
rename from src/plugins/remark-card.ts
rename to src/lib/unified/plugins/remark-card.ts
index e116470b..6a8f8b2b 100644
--- a/src/plugins/remark-card.ts
+++ b/src/lib/unified/plugins/remark-card.ts
@@ -1,28 +1,62 @@
import type { RemarkPlugin } from '@astrojs/markdown-remark';
-import type { BlockContent, DefinitionContent, Image, Link, Root } from 'mdast';
+import type { BlockContent, DefinitionContent, Root } from 'mdast';
import type { Plugin } from 'unified';
import { visit } from 'unist-util-visit';
-import { isLink, isList, isParagraph, isParent, isText } from './mdast-is';
+import { isLink, isList, isParagraph, isParent, isText } from '../mdast-is';
-const parseSign = (sign: string | undefined): string | undefined => {
+type BorderStyleMap = {
+ className: string;
+ markdownSymbol: string;
+};
+type RemarkCardOptions = {
+ borderStyles: BorderStyleMap[];
+};
+
+const defaultRemarkCardOptions: Readonly = {
+ borderStyles: [
+ {
+ className: 'solid',
+ markdownSymbol: '-',
+ },
+ {
+ className: 'double',
+ markdownSymbol: '=',
+ },
+ {
+ className: 'pixel',
+ markdownSymbol: '.',
+ },
+ ],
+};
+
+const parseSign = (
+ sign: string | undefined,
+ borderStyles: BorderStyleMap[],
+): string | undefined => {
if (sign === undefined || sign === '') return;
- const matched = sign.match(/@(?[-=.])?$/);
+ const defaultSymbol = borderStyles[0]?.markdownSymbol;
+ if (defaultSymbol === undefined) return;
+
+ const symbols = borderStyles.map((style) => style.markdownSymbol);
+ const reg = new RegExp(`@(?[${symbols.join()}])?$`);
+ const matched = sign.match(reg);
const borderTypeSign = matched?.groups?.borderType;
- const borderType =
- borderTypeSign === '-'
- ? 'solid'
- : borderTypeSign === '='
- ? 'double'
- : borderTypeSign === '.'
- ? 'pixel'
- : 'solid';
+ let borderType: string = defaultSymbol;
+
+ for (const style of borderStyles) {
+ if (borderTypeSign === style.markdownSymbol) {
+ borderType = style.className;
+ }
+ }
return borderType;
};
-const remarkCard: Plugin<[], Root> = (): ReturnType => {
+const remarkCard: Plugin<[RemarkCardOptions?], Root> = (
+ options = defaultRemarkCardOptions,
+): ReturnType => {
return (tree) => {
visit(tree, isList, (node) => {
if (!isParent(node)) return;
@@ -46,7 +80,7 @@ const remarkCard: Plugin<[], Root> = (): ReturnType => {
const [sign, ...rest] = cardSignText.split(/\s/);
const imageAlt = rest.join(' ');
- const borderType = parseSign(sign);
+ const borderType = parseSign(sign, options.borderStyles);
const cardListNode = listItemNode.children[1];
if (!isList(cardListNode)) continue;
@@ -66,36 +100,6 @@ const remarkCard: Plugin<[], Root> = (): ReturnType => {
if (cardImageNode.children.length === 0) continue;
const cardImageOrLink = cardImageNode.children[0];
- const imageMap = new Map<'url' | 'alt', string | null | undefined>();
- let imageNode: Image | Link;
- if (cardImageOrLink?.type === 'image') {
- imageMap.set('url', cardImageOrLink.url);
- imageMap.set('alt', imageAlt !== '' ? imageAlt : cardImageOrLink.alt);
- imageNode = {
- type: 'image',
- alt: imageMap.get('alt'),
- url: imageMap.get('url'),
- } as Image;
- } else if (isLink(cardImageOrLink)) {
- const cardImage = cardImageOrLink.children[0];
- if (cardImage?.type !== 'image') continue;
-
- imageMap.set('url', cardImage.url);
- imageMap.set('alt', imageAlt !== '' ? imageAlt : cardImage.alt);
- imageNode = {
- type: 'link',
- url: cardImageOrLink.url,
- children: [
- {
- type: 'image',
- alt: imageMap.get('alt'),
- url: imageMap.get('url'),
- } as Image,
- ],
- } as Link;
- } else {
- continue;
- }
const imageWrapperNode: BlockContent | DefinitionContent = {
type: 'paragraph',
@@ -106,9 +110,22 @@ const remarkCard: Plugin<[], Root> = (): ReturnType => {
className: 'card-image',
},
},
- children: [imageNode],
+ children: [],
};
+ if (cardImageOrLink?.type === 'image') {
+ cardImageOrLink.alt = cardImageOrLink.alt ?? imageAlt;
+ } else if (isLink(cardImageOrLink)) {
+ const cardImage = cardImageOrLink.children[0];
+ if (cardImage?.type !== 'image') continue;
+
+ cardImage.alt = cardImage.alt ?? imageAlt;
+ } else {
+ continue;
+ }
+
+ imageWrapperNode.children.push(cardImageOrLink);
+
const contentNode: BlockContent | DefinitionContent = {
type: 'paragraph',
data: {
diff --git a/src/plugins/remark-embed.ts b/src/lib/unified/plugins/remark-embed.ts
similarity index 93%
rename from src/plugins/remark-embed.ts
rename to src/lib/unified/plugins/remark-embed.ts
index ffe36848..b36a12a0 100644
--- a/src/plugins/remark-embed.ts
+++ b/src/lib/unified/plugins/remark-embed.ts
@@ -2,8 +2,8 @@ import type { RemarkPlugin } from '@astrojs/markdown-remark';
import type { Parent, Root } from 'mdast';
import type { Plugin } from 'unified';
import { visit } from 'unist-util-visit';
-import { isBareLink, isParent } from './mdast-is';
-import { type Transformer, getHName, getHProperties } from './transformers';
+import { isBareLink, isParent } from '../mdast-is';
+import { type Transformer, getHName, getHProperties } from '../transformers';
export type RemarkEmbedOptions = {
transformers: Transformer[];
diff --git a/src/plugins/remark-footnote.ts b/src/lib/unified/plugins/remark-footnote.ts
similarity index 97%
rename from src/plugins/remark-footnote.ts
rename to src/lib/unified/plugins/remark-footnote.ts
index e19158ee..f9212659 100644
--- a/src/plugins/remark-footnote.ts
+++ b/src/lib/unified/plugins/remark-footnote.ts
@@ -6,7 +6,7 @@ import {
isFootnoteDefinition,
isFootnoteReference,
isTextOrInlineCode,
-} from './mdast-is';
+} from '../mdast-is';
const remarkFootnote: Plugin<[], Root> = (): ReturnType => {
return (tree) => {
diff --git a/src/plugins/remark-line-breaks.ts b/src/lib/unified/plugins/remark-line-breaks.ts
similarity index 100%
rename from src/plugins/remark-line-breaks.ts
rename to src/lib/unified/plugins/remark-line-breaks.ts
diff --git a/src/plugins/remark-link-card.ts b/src/lib/unified/plugins/remark-link-card.ts
similarity index 93%
rename from src/plugins/remark-link-card.ts
rename to src/lib/unified/plugins/remark-link-card.ts
index 1577024b..c8706b91 100644
--- a/src/plugins/remark-link-card.ts
+++ b/src/lib/unified/plugins/remark-link-card.ts
@@ -2,7 +2,7 @@ import type { RemarkPlugin } from '@astrojs/markdown-remark';
import type { Parent, Root } from 'mdast';
import type { Plugin } from 'unified';
import { visit } from 'unist-util-visit';
-import { isBareLink, isParent } from './mdast-is';
+import { isBareLink, isParent } from '../mdast-is';
const remarkLinkCard: Plugin<[], Root> = (): ReturnType => {
return (tree) => {
diff --git a/src/plugins/transformers.ts b/src/lib/unified/transformers.ts
similarity index 100%
rename from src/plugins/transformers.ts
rename to src/lib/unified/transformers.ts
diff --git a/src/pages/[locale]/api/og/[collection]/[...slug].png.ts b/src/pages/[locale]/api/og/[collection]/[...slug].png.ts
index edd5bfd7..72c26099 100644
--- a/src/pages/[locale]/api/og/[collection]/[...slug].png.ts
+++ b/src/pages/[locale]/api/og/[collection]/[...slug].png.ts
@@ -1,5 +1,5 @@
import { getEntry } from 'astro:content';
-import { getOgImage } from '@/components/OgImage';
+import { getOgImage } from '@/components/models/OgImage';
import { getContentEntries } from '@/lib/collections/contents';
import { getLocaleFromSlug } from '@/utils/get-locale-from-slug';
import { getSlugWithoutLocale } from '@/utils/get-slug-without-locale';
diff --git a/src/pages/[locale]/blog/[...page].astro b/src/pages/[locale]/blog/[...page].astro
index 4ea2320f..af790ae2 100644
--- a/src/pages/[locale]/blog/[...page].astro
+++ b/src/pages/[locale]/blog/[...page].astro
@@ -1,7 +1,7 @@
---
import { getEntry } from 'astro:content';
-import { BlogList } from '@/components/BlogList';
-import { Pager } from '@/components/Pager';
+import { BlogList } from '@/components/models/BlogList';
+import { Pager } from '@/components/models/Pager';
import BaseLayout from '@/layouts/BaseLayout.astro';
import {
getLocaleContentEntries,
diff --git a/src/pages/[locale]/blog/archive/[date]/[...page].astro b/src/pages/[locale]/blog/archive/[date]/[...page].astro
index 15218302..72ef26d0 100644
--- a/src/pages/[locale]/blog/archive/[date]/[...page].astro
+++ b/src/pages/[locale]/blog/archive/[date]/[...page].astro
@@ -1,8 +1,8 @@
---
import { getEntry } from 'astro:content';
-import { BlogList } from '@/components/BlogList';
-import { formatDate } from '@/components/FormattedDate';
-import { Pager } from '@/components/Pager';
+import { BlogList } from '@/components/models/BlogList';
+import { formatDate } from '@/components/models/FormattedDate';
+import { Pager } from '@/components/models/Pager';
import BaseLayout from '@/layouts/BaseLayout.astro';
import {
getLocaleContentEntries,
diff --git a/src/pages/[locale]/blog/archive/index.astro b/src/pages/[locale]/blog/archive/index.astro
index 10690729..5b75a966 100644
--- a/src/pages/[locale]/blog/archive/index.astro
+++ b/src/pages/[locale]/blog/archive/index.astro
@@ -1,6 +1,6 @@
---
import { getEntry } from 'astro:content';
-import { FormattedDate } from '@/components/FormattedDate';
+import { FormattedDate } from '@/components/models/FormattedDate';
import BaseLayout from '@/layouts/BaseLayout.astro';
import { getSortedContentEntries } from '@/lib/collections/contents';
import { groupArchiveByYear } from '@/utils/group-archive-by-year';
diff --git a/src/pages/[locale]/blog/categories/[category]/[...page].astro b/src/pages/[locale]/blog/categories/[category]/[...page].astro
index 0d1624c8..be0d54ef 100644
--- a/src/pages/[locale]/blog/categories/[category]/[...page].astro
+++ b/src/pages/[locale]/blog/categories/[category]/[...page].astro
@@ -1,7 +1,7 @@
---
import { getEntry } from 'astro:content';
-import { BlogList } from '@/components/BlogList';
-import { Pager } from '@/components/Pager';
+import { BlogList } from '@/components/models/BlogList';
+import { Pager } from '@/components/models/Pager';
import BaseLayout from '@/layouts/BaseLayout.astro';
import {
getLocaleContentEntries,
diff --git a/src/pages/[locale]/blog/categories/index.astro b/src/pages/[locale]/blog/categories/index.astro
index 39d07265..a6366db7 100644
--- a/src/pages/[locale]/blog/categories/index.astro
+++ b/src/pages/[locale]/blog/categories/index.astro
@@ -1,6 +1,6 @@
---
import { getEntry } from 'astro:content';
-import { Taxonomy } from '@/components/Taxonomy';
+import { Taxonomy } from '@/components/models/Taxonomy';
import BaseLayout from '@/layouts/BaseLayout.astro';
import { getCategories } from '@/lib/collections/data';
import { langList } from '@/utils/i18n/data';
diff --git a/src/pages/[locale]/blog/tags/[tag]/[...page].astro b/src/pages/[locale]/blog/tags/[tag]/[...page].astro
index 98c87c5b..bd806f2c 100644
--- a/src/pages/[locale]/blog/tags/[tag]/[...page].astro
+++ b/src/pages/[locale]/blog/tags/[tag]/[...page].astro
@@ -1,7 +1,7 @@
---
import { getEntry } from 'astro:content';
-import { BlogList } from '@/components/BlogList';
-import { Pager } from '@/components/Pager';
+import { BlogList } from '@/components/models/BlogList';
+import { Pager } from '@/components/models/Pager';
import BaseLayout from '@/layouts/BaseLayout.astro';
import {
getLocaleContentEntries,
diff --git a/src/pages/[locale]/blog/tags/index.astro b/src/pages/[locale]/blog/tags/index.astro
index 8e6a8007..3c0311bc 100644
--- a/src/pages/[locale]/blog/tags/index.astro
+++ b/src/pages/[locale]/blog/tags/index.astro
@@ -1,6 +1,6 @@
---
import { getEntry } from 'astro:content';
-import { Taxonomy } from '@/components/Taxonomy';
+import { Taxonomy } from '@/components/models/Taxonomy';
import BaseLayout from '@/layouts/BaseLayout.astro';
import { getTags } from '@/lib/collections/data';
import { langList } from '@/utils/i18n/data';
diff --git a/src/pages/[locale]/index.astro b/src/pages/[locale]/index.astro
index 90fdbcb5..cc9c1daf 100644
--- a/src/pages/[locale]/index.astro
+++ b/src/pages/[locale]/index.astro
@@ -1,9 +1,9 @@
---
import { getEntry } from 'astro:content';
-import { BlogList } from '@/components/BlogList';
-import { BulletinBoard } from '@/components/BulletinBoard';
-import { Icon } from '@/components/Icon';
-import { PhotoGallery } from '@/components/PhotoGallery';
+import { BlogList } from '@/components/models/BlogList';
+import { BulletinBoard } from '@/components/ui/BulletinBoard';
+import { Icon } from '@/components/ui/Icon';
+import { PhotoGallery } from '@/components/ui/PhotoGallery';
import BaseLayout from '@/layouts/BaseLayout.astro';
import { getSortedContentEntries } from '@/lib/collections/contents';
import {
diff --git a/src/pages/[locale]/news/[...page].astro b/src/pages/[locale]/news/[...page].astro
index 3de08225..77974abe 100644
--- a/src/pages/[locale]/news/[...page].astro
+++ b/src/pages/[locale]/news/[...page].astro
@@ -1,8 +1,8 @@
---
import { getEntry } from 'astro:content';
-import { FormattedDate } from '@/components/FormattedDate';
-import { Icon } from '@/components/Icon';
-import { Pager } from '@/components/Pager';
+import { FormattedDate } from '@/components/models/FormattedDate';
+import { Pager } from '@/components/models/Pager';
+import { Icon } from '@/components/ui/Icon';
import BaseLayout from '@/layouts/BaseLayout.astro';
import {
getLocaleContentEntries,
diff --git a/src/pages/api/og/[collection]/[...slug].png.ts b/src/pages/api/og/[collection]/[...slug].png.ts
index a23b4968..2751b52e 100644
--- a/src/pages/api/og/[collection]/[...slug].png.ts
+++ b/src/pages/api/og/[collection]/[...slug].png.ts
@@ -1,5 +1,5 @@
import { getEntry } from 'astro:content';
-import { getOgImage } from '@/components/OgImage';
+import { getOgImage } from '@/components/models/OgImage';
import { getContentEntries } from '@/lib/collections/contents';
import { getSlugWithoutLocale } from '@/utils/get-slug-without-locale';
import { defaultLang } from '@/utils/i18n/data';
diff --git a/src/pages/blog/[...page].astro b/src/pages/blog/[...page].astro
index 69c95a31..3dd9dc98 100644
--- a/src/pages/blog/[...page].astro
+++ b/src/pages/blog/[...page].astro
@@ -1,7 +1,7 @@
---
import { getEntry } from 'astro:content';
-import { BlogList } from '@/components/BlogList';
-import { Pager } from '@/components/Pager';
+import { BlogList } from '@/components/models/BlogList';
+import { Pager } from '@/components/models/Pager';
import BaseLayout from '@/layouts/BaseLayout.astro';
import { getSortedContentEntries } from '@/lib/collections/contents';
import { LIMIT_PER_PAGE } from '@/lib/consts';
diff --git a/src/pages/blog/archive/[date]/[...page].astro b/src/pages/blog/archive/[date]/[...page].astro
index ef1931cf..21fc5fe2 100644
--- a/src/pages/blog/archive/[date]/[...page].astro
+++ b/src/pages/blog/archive/[date]/[...page].astro
@@ -1,8 +1,8 @@
---
import { getEntry } from 'astro:content';
-import { BlogList } from '@/components/BlogList';
-import { formatDate } from '@/components/FormattedDate';
-import { Pager } from '@/components/Pager';
+import { BlogList } from '@/components/models/BlogList';
+import { formatDate } from '@/components/models/FormattedDate';
+import { Pager } from '@/components/models/Pager';
import BaseLayout from '@/layouts/BaseLayout.astro';
import { getSortedContentEntries } from '@/lib/collections/contents';
import { LIMIT_PER_PAGE } from '@/lib/consts';
diff --git a/src/pages/blog/archive/index.astro b/src/pages/blog/archive/index.astro
index d2c91dbf..0f2989fc 100644
--- a/src/pages/blog/archive/index.astro
+++ b/src/pages/blog/archive/index.astro
@@ -1,6 +1,6 @@
---
import { getEntry } from 'astro:content';
-import { FormattedDate } from '@/components/FormattedDate';
+import { FormattedDate } from '@/components/models/FormattedDate';
import BaseLayout from '@/layouts/BaseLayout.astro';
import { getSortedContentEntries } from '@/lib/collections/contents';
import { groupArchiveByYear } from '@/utils/group-archive-by-year';
diff --git a/src/pages/blog/categories/[category]/[...page].astro b/src/pages/blog/categories/[category]/[...page].astro
index bc294c02..757d5763 100644
--- a/src/pages/blog/categories/[category]/[...page].astro
+++ b/src/pages/blog/categories/[category]/[...page].astro
@@ -1,7 +1,7 @@
---
import { getEntry } from 'astro:content';
-import { BlogList } from '@/components/BlogList';
-import { Pager } from '@/components/Pager';
+import { BlogList } from '@/components/models/BlogList';
+import { Pager } from '@/components/models/Pager';
import BaseLayout from '@/layouts/BaseLayout.astro';
import { getSortedContentEntries } from '@/lib/collections/contents';
import { getCategories } from '@/lib/collections/data';
diff --git a/src/pages/blog/categories/index.astro b/src/pages/blog/categories/index.astro
index 400a9d04..e5fff617 100644
--- a/src/pages/blog/categories/index.astro
+++ b/src/pages/blog/categories/index.astro
@@ -1,6 +1,6 @@
---
import { getEntry } from 'astro:content';
-import { Taxonomy } from '@/components/Taxonomy';
+import { Taxonomy } from '@/components/models/Taxonomy';
import BaseLayout from '@/layouts/BaseLayout.astro';
import { getCategories } from '@/lib/collections/data';
import { defaultLang } from '@/utils/i18n/data';
diff --git a/src/pages/blog/tags/[tag]/[...page].astro b/src/pages/blog/tags/[tag]/[...page].astro
index a40695e2..a56681db 100644
--- a/src/pages/blog/tags/[tag]/[...page].astro
+++ b/src/pages/blog/tags/[tag]/[...page].astro
@@ -1,7 +1,7 @@
---
import { getEntry } from 'astro:content';
-import { BlogList } from '@/components/BlogList';
-import { Pager } from '@/components/Pager';
+import { BlogList } from '@/components/models/BlogList';
+import { Pager } from '@/components/models/Pager';
import BaseLayout from '@/layouts/BaseLayout.astro';
import { getSortedContentEntries } from '@/lib/collections/contents';
import { getTags } from '@/lib/collections/data';
diff --git a/src/pages/blog/tags/index.astro b/src/pages/blog/tags/index.astro
index b6cc50db..3356533e 100644
--- a/src/pages/blog/tags/index.astro
+++ b/src/pages/blog/tags/index.astro
@@ -1,6 +1,6 @@
---
import { getEntry } from 'astro:content';
-import { Taxonomy } from '@/components/Taxonomy';
+import { Taxonomy } from '@/components/models/Taxonomy';
import BaseLayout from '@/layouts/BaseLayout.astro';
import { getTags } from '@/lib/collections/data';
import { defaultLang } from '@/utils/i18n/data';
diff --git a/src/pages/index.astro b/src/pages/index.astro
index 2df94313..049d6897 100644
--- a/src/pages/index.astro
+++ b/src/pages/index.astro
@@ -1,9 +1,9 @@
---
import { getEntry } from 'astro:content';
-import { BlogList } from '@/components/BlogList';
-import { BulletinBoard } from '@/components/BulletinBoard';
-import { Icon } from '@/components/Icon';
-import { PhotoGallery } from '@/components/PhotoGallery';
+import { BlogList } from '@/components/models/BlogList';
+import { BulletinBoard } from '@/components/ui/BulletinBoard';
+import { Icon } from '@/components/ui/Icon';
+import { PhotoGallery } from '@/components/ui/PhotoGallery';
import BaseLayout from '@/layouts/BaseLayout.astro';
import { getSortedContentEntries } from '@/lib/collections/contents';
import {
diff --git a/src/pages/news/[...page].astro b/src/pages/news/[...page].astro
index 433193f3..21ac6ccc 100644
--- a/src/pages/news/[...page].astro
+++ b/src/pages/news/[...page].astro
@@ -1,8 +1,8 @@
---
import { getEntry } from 'astro:content';
-import { FormattedDate } from '@/components/FormattedDate';
-import { Icon } from '@/components/Icon';
-import { Pager } from '@/components/Pager';
+import { FormattedDate } from '@/components/models/FormattedDate';
+import { Pager } from '@/components/models/Pager';
+import { Icon } from '@/components/ui/Icon';
import BaseLayout from '@/layouts/BaseLayout.astro';
import { getSortedContentEntries } from '@/lib/collections/contents';
import { LIMIT_PER_PAGE } from '@/lib/consts';
diff --git a/src/plugins/rehype-image-figure.ts b/src/plugins/rehype-image-figure.ts
deleted file mode 100644
index 3e787a6b..00000000
--- a/src/plugins/rehype-image-figure.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import type { RehypePlugin } from '@astrojs/markdown-remark';
-import type { Root } from 'hast';
-import type { Plugin } from 'unified';
-import { visit } from 'unist-util-visit';
-
-const rehypeMarkImageFigure: Plugin<
- [],
- Root
-> = (): ReturnType => {
- return (tree) => {
- visit(tree, 'element', (node) => {
- if (!Object.hasOwn(node.properties, 'dataImageFigure')) return;
- node.tagName = 'figure';
- });
- };
-};
-
-export default rehypeMarkImageFigure;
diff --git a/src/plugins/remark-astro-image-assets.ts b/src/plugins/remark-astro-image-assets.ts
deleted file mode 100644
index a3c2571d..00000000
--- a/src/plugins/remark-astro-image-assets.ts
+++ /dev/null
@@ -1,111 +0,0 @@
-import fs from 'node:fs';
-import path from 'node:path';
-import type { RemarkPlugin } from '@astrojs/markdown-remark';
-import type { Image, Parent, Root } from 'mdast';
-import sharp from 'sharp';
-import type { Plugin } from 'unified';
-import { visit } from 'unist-util-visit';
-
-type RemarkAstroImageAssetsOptions = {
- imgDir: string;
- size: number;
- blurFormat: keyof sharp.FormatEnum;
- widths: number[];
- sizes: string;
-};
-
-const defaultRemarkAstroImageAssetsOptions: Readonly =
- {
- imgDir: './assets/images',
- size: 8,
- blurFormat: 'webp',
- widths: [240, 540, 720],
- sizes:
- '(max-width: 360px) 240px, (max-width: 720px) 540px, (max-width: 1600px) 720px',
- };
-
-const remarkAstroImageAssets: Plugin<[RemarkAstroImageAssetsOptions?], Root> = (
- options = defaultRemarkAstroImageAssetsOptions,
-): ReturnType => {
- return async (tree) => {
- const imgAndParentPairs: { node: Image; parent: Parent }[] = [];
-
- visit(tree, 'image', (node, index, parent) => {
- if (
- parent?.type !== 'paragraph' ||
- index !== 0 ||
- node.url.startsWith('http')
- )
- return;
-
- imgAndParentPairs.push({ node, parent });
- });
-
- const { imgDir, size, blurFormat, sizes, widths } = options;
-
- await Promise.all(
- imgAndParentPairs.map(async ({ node, parent }) => {
- const basename = path.basename(node.url);
- const buffer = fs.readFileSync(
- path.join(process.cwd(), './src', imgDir, basename),
- );
-
- const metadataPromise = sharp(buffer)
- .metadata()
- .then((data) => {
- if (!data.width || !data.height) {
- throw new Error(`Failed to get image metadata: ${node.url}`);
- }
-
- return {
- width: data.width,
- height: data.height,
- aspectRatio: `${data.width} / ${data.height}`,
- };
- });
-
- const base64Promise = sharp(buffer)
- .resize(size, size, { fit: 'inside' })
- .toFormat(blurFormat, { quality: 60 })
- .modulate({
- brightness: 1,
- saturation: 1.2,
- })
- .normalize()
- .toBuffer()
- .then(
- (data) =>
- `data:image/${blurFormat};base64,${data.toString('base64')}`,
- );
-
- const [{ width, aspectRatio }, base64] = await Promise.all([
- metadataPromise,
- base64Promise,
- ]);
-
- node.data = {
- ...node.data,
- hProperties: {
- ...(node.data?.hProperties ?? {}),
- widths: [...widths, width],
- sizes: `${sizes}, ${width}px`,
- format: 'avif',
- },
- };
-
- parent.data = {
- ...parent.data,
- hProperties: {
- ...(parent.data?.hProperties ?? {}),
- dataImageFigure: true,
- dataImageAlt: node.alt,
- dataImageAspectRatio: aspectRatio,
- dataImageBlurUrl: `url("${base64}")`,
- },
- };
- }),
- );
- };
-};
-
-export default remarkAstroImageAssets;
diff --git a/tsconfig.json b/tsconfig.json
index d12458e6..91156d19 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,4 +1,5 @@
{
+ "$schema": "https://json.schemastore.org/tsconfig",
"extends": "astro/tsconfigs/strictest",
"compilerOptions": {
"strictNullChecks": true,
@@ -6,15 +7,40 @@
"esModuleInterop": true,
"jsx": "preserve",
"jsxImportSource": "solid-js",
+ "lib": [
+ "ESNext",
+ "DOM"
+ ],
+ "target": "ESNext",
+ "module": "ESNext",
+ "moduleDetection": "force",
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "verbatimModuleSyntax": true,
+ "noEmit": true,
+ "strict": true,
+ "skipLibCheck": true,
+ "noFallthroughCasesInSwitch": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ // "noPropertyAccessFromIndexSignature": true,
"baseUrl": ".",
"paths": {
"@/*": [
"./src/*"
]
- }
+ },
+ "plugins": [
+ {
+ "name": "@mdx-js/typescript-plugin"
+ },
+ {
+ "name": "@astrojs/ts-plugin"
+ }
+ ]
},
"exclude": [
"./dist",
"./node_modules"
- ]
+ ],
}