ポートフォリオを新しくした

#astro#フロントエンド

ポートフォリオを新しくしました。

GitHub - ikura-hamu/portfolio2
GitHub - ikura-hamu/portfolio2
https://github.com/ikura-hamu/portfolio2

目次

ここが変わった

  • ブログがついた
  • かっこいい

使った技術

astro

フロントエンドのフレームワークです。

Astroは、ブログやマーケティング、eコマースなど、コンテンツ駆動のウェブサイトを作成するためのウェブフレームワークです。Astroは、新しいフロントエンドアーキテクチャを開拓し、他のフレームワークと比較してJavaScriptのオーバーヘッドと複雑さを低減することで知られています。高速でSEOに優れたウェブサイトが必要なら、Astroが最適です。

traPの先輩のmazreanさんがポートフォリオで使っていたのを見て、よさそうだったので使いました。
(mazreanさんのポートフォリオはこちら→ https://mazrean.com)

実際に使ってみて、コンテンツコレクションが便利だと感じました。

コンテンツコレクション
コンテンツコレクション
https://docs.astro.build/ja/guides/content-collections/

コンテンツコレクションは、markdownやyamlなどのドキュメントやデータを、TypeScriptの型の恩恵を受けながら管理して扱うことができる仕組みです。このブログの内容やaboutページの技術とかのやつはコンテンツコレクションで管理しています。

import {z} from 'astro:content'

export const skills = z.array(z.object({
  name: z.string(),
  level: z.number(),
  description: z.string(),
  icon: z.string(),
}))

こんな感じでスキーマを定義して、

- go:
  name: Go
  level: 3
  description: 普段何か作るときはだいたいGoを使います
  icon: devicon:go
- python:
  name: Python
  level: 2
  description: 競プロや何かさくっと作るときはPythonを使います
  icon: devicon:python
# 省略

こんな感じで内容を書きます。これをsrc/content/skillとかに置いておきます。

import { getEntry } from "astro:content";

const allSkills = await getEntry("skill", "skills");

すると、こんな感じで取得出来て、良い感じに扱えます。便利ですね。

また、テンプレートも充実していて、何もしなくてもちゃんとスタイルのついた状態から始められるので、とても楽でした。

Themes | Astro
Themes | Astro
https://astro.build/themes/

tailwind css

自分はスタイリング(というよりcss)があまり好きではないのですが、去年の年末の冬ハッカソンでNext.jsでフロントを書いたときにtailwindを使って、結構楽しかったので今回も使いました。astroのテンプレートは普通のCSSで書かれているので、すべてを移行したわけではなく普通のとtailwindがどっちも入っているのですが、それでも動いているので楽でいいです。

Tailwind CSS - Rapidly build modern websites without ever leaving your HTML.
Tailwind CSS - Rapidly build modern websites without ever leaving your HTML.
https://tailwindcss.com/

Vercel

デプロイ先。特に理由は無いです。

こだわり

特に強くこだわったところがあるわけではないのですが、いい感じにできたと思うのはOGPのカードです。
↓こんな感じです。

GitHub: Let’s build from here
GitHub: Let’s build from here
https://github.com

URLを指定するとカードを表示してくれます。
使用技術によってはCORSとかで面倒なことがありますが、Astroはビルド時に原則すべてのJavaScriptを実行してブラウザ上での実行が無いので、CORSの問題が発生しません。下のようなコンポーネントを用意して、mdxファイルでインポートしてブログを書いています。

---
import { JSDOM } from "jsdom";

const { url } = Astro.props;

const fetchOgp = async (url: string) => {
  const res = await fetch(url);
  const text = await res.text();
  const doms = new JSDOM(text);
  const metas = doms.window.document.getElementsByTagName("meta");

  const metaData = {
    title: "",
    description: "",
    image: "",
  };

  for (let i = 0; i < metas.length; i++) {
    const meta = metas[i];
    if (meta.getAttribute("property") === "og:title") {
      metaData.title = meta.getAttribute("content") ?? "";
    }
    if (meta.getAttribute("property") === "og:description") {
      metaData.description = meta.getAttribute("content") ?? "";
    }
    if (meta.getAttribute("property") === "og:image") {
      metaData.image = meta.getAttribute("content") ?? "";
    }
  }

  return metaData;
};

const metaData = await fetchOgp(url);
---

<a href={url} class="py-0 my-0">
  <div
    class="max-w-full h-28 border-2 border-primary rounded bg-gray-100 hover:bg-gray-300 hover:shadow-lg transition-all duration-300 ease-in-out overflow-hidden"
  >
    {
      metaData.image && (
        <div class="grid grid-cols-[30%_70%] h-full content-center items-center">
          <img
            src={metaData.image}
            alt={metaData.title}
            class="max-h-full w-auto object-center object-cover"
          />
          <div class="px-2">
            <h5 class="truncate">{metaData.title}</h5>
            <div class="text-xs">{url}</div>
            <div class="truncate text-sm">{metaData.description}</div>
          </div>
        </div>
      )
    }
    {
      !metaData.image && (
        <div class="grid h-full content-center items-center">
          <div class="px-2">
            <h5 class="truncate">{metaData.title}</h5>
            <div class="text-xs">{url}</div>
            <div class="truncate text-sm">{metaData.description}</div>
          </div>
        </div>
      )
    }
  </div>
</a>

実装するときにはこの記事を参考にしました。ありがとうございました。

自分のウェブサイトにブログカードを実装してみた
自分のウェブサイトにブログカードを実装してみた
https://zenn.dev/tomi/articles/2021-03-22-blog-card

おわり

おわりです。自分専用のブログが欲しいと思っていてついに念願かなったわけですが、当面はtraPのブログに書く気がします。こっちには何を書くんだろう。自慢のOGPカードを置いて終わりにします。

ikura-hamu - 東京工業大学デジタル創作同好会traP
https://trap.jp/author/ikura-hamu
SysAd班、ゲーム班 いろいろやりたい