🥥

AstroとNewtを使ってブログサイトを作る②

2023/08/10に公開

AstroとNewtで個人ブログを作成する記事の第二回目になります。

第一回
- Astroとは?Newtとは?
- チュートリアルの紹介
- 使ったテンプレートの紹介

第二回
- サイトの構築手順

第三回
- サーバー構築手順
- デプロイ→サイト公開!

今回は、サイトの構築手順について書いていきます。

第一回目と第三回目の記事はこちら!

https://zenn.dev/karabiner_inc/articles/b9b1d1c85bf1d2
https://zenn.dev/karabiner_inc/articles/627fcc601445a7

作ったブログサイトはこれです。良ければ覗いていってください^^

https://blog.romy-will-become-dragon.com/

対象者

  • バックエンドの実装をせずにサイト構築したい方
  • 個人サイトが作りたい方
  • AstroのこともNewtのことも何となく知っている方
  • Astroのテンプレートの使い方を知りたい方

動作環境・前提

バージョン
Mac 13.x
npm 8.11.0
Astro 2.8.5
newt-client-js 3.2.4

サイトの構築手順

Newtのチュートリアルをやってみる

実際に作り始める前に、まずはチュートリアルをやってみましょう。

もうやってるよ!って方は、次に進んでもらって大丈夫です。

以下は、Newtの公式サイトにあるチュートリアルです。

https://www.newt.so/docs/tutorials/get-contents-in-astro

Astroのセットアップから始まって、Newtのセットアップ、NewtのAPIクライアント作成とそれをAstroで使う方法、記事の表示方法といった流れで、今回やりたいことが全部詰まってます。

いきなりオリジナルのサイトを作り始めても悪くはないと思いますが、開発の流れを掴むためにもまずは一通りチュートリアルをやってみることをお勧めします。

多少詰まったりしても、1時間もあれば全部できると思うので、気軽にサクッと触ってみてください。

テンプレートを選ぶ

ここでは、ブログサイトに使用したいテンプレートを選んでいきましょう。

以下が、Astroのテンプレート一覧です。

https://astro.build/themes/

中には有料の物もありますが、無料でもオシャレな物がたくさんありますね。ありがたや…!

僕は今回以下のテンプレートを使用しました。

https://astro.build/themes/details/simple-blog-template/

選んだ理由は、めっちゃシンプルでカスタムしやすそうだったからです。

僕、HTMLとCSSは読めるし書けるんですが、JSは簡単なものしか読めないし書けなくて、あんまりオシャレすぎるとコード難しくて全然カスタマイズする余地がない!てなりそうだったので…

皆さんも、コードをしっかり確認してご自身のレベルに合ったテンプレートを選んでみてください。

新しいプロジェクトを作成する

さて、いよいよブログサイトの開発に着手していきます。

まずは、使いたいテンプレートのGithubを開きましょう。

https://github.com/OnWritingCode/simple-blog-template

大体、GithubのREADMEにテンプレートを使った新規プロジェクトの作り方が説明してあると思うので、それに従ってプロジェクトを新しく作成してください。

コマンドを実行したら、チュートリアルの時と同じように色々質問されると思うので、こちらもチュートリアルの時と同じように答えてあげてください。

プロジェクトが作成できたら、開発サーバーを立ち上げて、http://localhost:3000/にアクセスしてみましょう。

今度はチュートリアルの時とは異なり、選んだテンプレートのLive demoのような画面が出てきたと思います。

※ テンプレートによっては異なる場合があります。

この画面が見れたら、プロジェクトの作成は完了です!

カスタマイズ① Newtと連携させる

それでは、テンプレートをカスタマイズしていきましょう。

まずは、Newtで書いた記事を表示するために、Newtと連携させていきます。

連携させる作業自体は、ほぼチュートリアルのまんまで大丈夫です。

ただし、チュートリアルの時とはディレクトリ構成が変わっていると思うので、照らし合わせながら上手くやってください。

以下は僕が行ったカスタマイズの例です。

デフォルトのディレクトリ構造はこんな感じでした(README参照)。

/
├── public
└── src
    ├── components
    │   ├── layouts
    │   └── utilities
    ├── content
    ├── pages
    └── style

この内、以下のファイルを追加・修正して、Newtの記事を表示させることに成功しました。

/
├── public
└── src
    ├── components
    │   ├── blog
+   │   │   └── preview.astro <- 修正
    │   ├── layouts
    │   └── utilities
    ├── content
+   ├── lib
+   │   └── newt.ts  <- 追加
    ├── pages
    │   ├── articles
+   │   │   └── [slug].astro <- 追加
+   │   └── index.astro <- 修正
    └── style

各ファイルのコードも置いておきます。
(分量が多いためアコーディオンにしておきます。適宜確認したいファイルのものを展開してご覧ください。)

/src/components/blog/preview.astro
---
import type {Article} from '../../lib/newt';
import Date from "@components/utilities/Date";

const article: Article = Astro.props.article
---

<div class="cover-box">
	<a class="slug-link" href={`/articles/${article.slug}`}>
		<h2>
			{article.title}
			<p class="date" style="font-size: 50%;"><Date date={article.first_date}/></p>
			<img src={article.coverImage["src"]} />
		</h2>
		<div class="dark-cover"></div>
	</a>
</div>

<style>
	h2 {
		background-color: hsl(188 8% 95%);
		width: auto;
		padding: 5%;
	}

	.slug-link {
		color: hsl(188 5% 27%);
		text-decoration: none;
	}

	.cover-box {
		position: relative;
	}

	img {
		margin-top: 3%;
		width: 100%;
		height: 300px;
		object-fit: cover;
	}

	.dark-cover {
		position: absolute;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		z-index: 1;
		opacity: .1;
	}

	.dark-cover:hover {
		background-color: black;
	}
</style>
/src/lib/newt.ts
import { createClient } from "newt-client-js"

export interface Article{
    title: string
    slug: string
    body: string
    coverImage: object
    tags: []
}

export const newtClient = createClient({
    spaceUid: import.meta.env.NEWT_SPACE_UID,
    token: import.meta.env.NEWT_CDN_API_TOKEN,
    apiType: 'cdn',
})
/src/pages/articles/[slug].astro
---
import Blog from "@layouts/blog";
import Date from "@components/utilities/Date";

import {newtClient} from '../../lib/newt'
import type {Article} from '../../lib/newt'

export async function getStaticPaths({ rss }) {
    const {items: articles} = await newtClient.getContents<Article>({
        appUid: 'blog2',
        modelUid: 'article',
        query: {
            select: ['title', 'meta', 'slug', 'body', 'coverImage', 'tags', 'first_date', 'update_date'],
        },
    })
    return articles.map((article)=>({
        params: {slug: article.slug},
        props: {article},
    }))
}

// Destructure to get both `Astro.props.post` and `Astro.props.post.Content`
const { article } = Astro.props;
---

<Blog title={article.meta.title} description={article.meta.description}>
	<div class="post-header container">
		<h1 class="post-title">{article.title}</h1>
		<div class="post-date">
			<p>公開日:<Date date={article.first_date}/></p>
			{
				article.update_date === "" ? (
					<p></p>
				) : (
					<p>更新日:<Date date={article.update_date}/></p>
				)
			}
		</div>
		<img src={article.coverImage["src"]} />
	</div>
	<div class="content container">
        <!-- set:htmlはXSS攻撃の危険がある。今回はNewtで作成された記事以外を受け付けないので、安全としている -->
        <article set:html={article.body} />
	</div>
</Blog>


<style>
	.post-header {
		margin-top: 60px;
		margin-bottom: 40px;
	}
	.post-date {
		font-size: 0.75rem;
	}

	.content {
		margin-bottom: 40px;
	}
</style>
/src/pages/index.astro
---
import Blog from "@layouts/blog";
import Preview from "@components/blog/preview";

import {newtClient} from '../lib/newt'
import type {Article} from '../lib/newt'

const {items: articles} = await newtClient.getContents<Article>({
	// https://app.newt.so/romy-will-become-dragon/apps/blog2/settings/general に書いてあるやつ
	appUid: 'blog2',
	modelUid: 'article',
	query: {
		select: ['title', 'slug', 'body', 'coverImage', 'tags', 'first_date']
	},
})
---

<Blog title="ろみぃちゃんはドラゴンになりたい" description="ろみぃちゃんが雑多に書くブログ">
	<div class="content container">
		{articles.map((a) => <Preview article={a} />)}
	</div>
</Blog>


決してこれが正解、というわけではないので、ご自身のやりやすい方法でカスタマイズされるのが良いかと思います。

今後どんな感じにサイトを発展させていきたい、みたいなイメージが既にある方は、そこから逆算してディレクトリ構造を考えるとかでも良さそうですね。

カスタマイズ② 画面のレイアウトを整える

テンプレートのままではオリジナリティが出ないので、ちょこっとデザインを変えてカスタマイズしていきましょう。

ここは特に解説することはないです。

皆さんの思うように、存分にカスタマイズしちゃってください!

一例として、僕が作ったブログサイトの記事一覧画面をお見せしますね。

ちょっと恥ずかしいのでモザイクかけました笑
どうせサイト開いたらすぐ見えるんですけどね、、

テンプレートのLive demoと比べると、大分味気なさが無くなっていると思います!

タイトルの横にSNSのアイコン置いてリンク張るやつ、やってみたかったんですよね〜 満足。

皆さんも、是非「こんなデザインにしたい」「こういうの付けてみたい」を形にしていってください!

最後に

今回は、ローカル環境で新規プロジェクトを構築し、テンプレートをカスタマイズするところまでやりました。

どうでしょう?結構簡単だったんじゃないでしょうか?

次回はサーバーの構築をやりますので、是非そちらもご覧ください!

カラビナテクノロジー デベロッパーブログ

Discussion