herohoroブログ

Awesome初改造!_Setup&ファイル同士のつながりをたどってNotionDBのDescriptionとAuthorsを表示せる方法



🔄   2023-08-20

6月にNotion blogのAwesome(https://github.com/steelydylan/Awesome)を使いはじめました。

mosyaのコミュニティでちょっと図々しい投稿をしてみたのがキッカケ。

image block

ずっとエラーで

手も足も出せなかったリポジトリを無事に公開できたときの感動は格別🎉

このAwesomeブログを使って2ヶ月経ちました。

いつものことながら使えば使うほど愛着が湧いてきて、Notion blogの面白さを堪能できるようになってきました。

この記事ではその面白さをコードに乗せてお伝えできればと思います 🥳

🐣
初期の詳しい設定はmosyaのブログにあります!

Awesomeブログを立ち上げるために必要な設定や、

実際に私のブログ(https://like.herohoro.com/)で使っているカスタマイズ方法について紹介します☆

設定はblog.config.ts

ブログを使う際に、最低限必要なカスタマイズはblog.config.tsに集約されています。

blog.config.tsの全コード

https://github.com/steelydylan/Awesome/blob/master/blog.config.ts

私のブログでカスタマイズした項目をピックアップすると….

  • siteName
  • title
  • description
image block

  • styles
image block

  • hero
image block

  • navigation
image block

  • account
image block

  • categories
image block

image block

コード:https://github.com/steelydylan/Awesome/blob/master/blog.config.ts

この他に、ブログのタイトルを変更する場合は…

public>Images>logo.svgをいじります

https://github.com/steelydylan/Awesome/blob/master/public/images/logo.svg?short_path=1632d17

<svg xmlns="http://www.w3.org/2000/svg" width="201" height="39" viewBox="0 0 201 39">
  <text id="AWESOME." transform="translate(0 31)" fill="#2c2c2c" font-size="30" font-family="Futura-Bold, Futura" font-weight="700" letter-spacing="0.1em"><tspan x="0" y="0">AWESOME.</tspan></text>
</svg>

画像の保管場所はCloudflare R2

解説記事の方で詳しく手順が書かれています。

image block

https://mosya.dev/blog/awesome#cloudflareの設定

途中、クレジットカードの登録があるのでドキドキしますが、

今のところ特に請求されてない….ぽいです👀


ここまで設定ができると基本的なことは満足して使えるようになります(*๓´╰╯`๓)♡

https://64dcfa1e3a3410009ac66c9f--tranquil-kulfi-a42dcf.netlify.app/horomi

ただ、easy-notion-blog….いや、astro-notion-blogで対応しているNotionブロックはまだサポートされていません。

https://like.herohoro.com/sample/block-check

でも、AwesomeはAwesomeの良さがあるなと思っています。

デザインもそうですし、

blog.config.txで大体のことが済んでしまうのも嬉しいですし、

subNavigationをblog.config.txで設定してしまえば固定ページのように扱えることにも驚きました。

image block

subNavigation: [
    {
      name: "terms",
      url: "/about/terms",
    },
    {
      name: "privacy",
      url: "/about/privacy",
    },
    {
      name: "GitHub",
      url: "https://github.com/steelydylan/Awesome",
    },
  ],
blog.config.tx
image block

image block

Notionプロパティを全てAwesomeで表示させたい

使い始めて1ヶ月を経過したあたりで….

複製したNotionDBにあるプロパティの中でAwesomeに反映されていないプロパティをどうしてもつなげたくなってきました。(改造魂っ!!!

image block

https://mint-hardware-b22.notion.site/73b60eecc10f4e74a4e9e8cd6a8b3a6e?v=ec2d1ecf153146679b44dc21fa54dc7a

NotionAPIへの経路

Awesomeで表示されているディレクトリから

NotionAPIのあるファイルまでどういう経路を辿っているのかを調べてみました。

Next.js13のpagesタイプなので….

pages>index.tsxがトップページの記事一覧になります。

image block

pages>index.tsx
pages>index.tsxの全コード:

https://github.com/steelydylan/Awesome/blob/master/pages/index.tsx

propsのarticlesでgetFilteredArticlesが代入されています。

export const getStaticProps = async () => {
  const articles = await getArticles();

  return {
    revalidate: 60,
    props: {
      current: 0,
      max: Math.ceil(articles.length / blogConfig.article.articlesPerPage),
      articles: await getFilteredArticles({
        current: 0,
      }),
    },
  };
};
pages>index.tsxの一部

getStaticPropsについて:

In the pages directory, the getStaticProps function is used to pre-render a page at build time. This function can be used to fetch data from an external API or directly from a database, and pass this data down to the entire page as it's being generated during the build.

utiles>get-articles.tsx
utiles>get-articles.tsxの全コード:

https://github.com/steelydylan/Awesome/blob/master/utils/get-articles.ts

articles変数でgetArticlesが代入されています👀

export const getFilteredArticles = async ({
  current,
  categoryId,
  tagId,
}: {
  current: number;
  categoryId?: string;
  tagId?: string;
}) => {
  const articles = await getArticles();
  const results = articles
    .filter(({ data }) => {
      if (!categoryId) {
        return true;
      }
      return data.category === categoryId;
    })
utiles>get-articles.tsxの一部

同じファイル内にgetArticles関数があります。

blog.config.tsのuseをnotionとした場合に、getDatabase関数を動かすようです👀

export const getArticles = async (): Promise<Article[]> => {
  if (blogConfig.use === "notion") {
    return getDatabase(process.env.NOTION_DATABASE_ID as string, {
      sorts: [
        {
          property: "rEYP",
          direction: "descending",
        },
      ],
    });
  }
  return getArticlesFromFile();
};
utiles>get-articles.tsxの一部

utils>notion.tsx

utils>notion.tsxの全コード:

https://github.com/steelydylan/Awesome/blob/master/utils/notion.tsx

素敵な眺めです 😍

export const getDatabase = async (
  databaseId: string,
  args: Omit<QueryDatabaseParameters, "database_id"> = {}
) => {
  const response = await notion.databases.query({
    database_id: databaseId,
    ...args,
  });
  const { results } = response;
  const posts = await Promise.all(
    results.map(async (result: PageObjectResponse) => {
      const d = result.properties;
      const item = {
        thumbnail: "",
        authors: "",
        slug: "",
        published: "no",
        date: "",
        description: "",
        page: "",
        id: result.id,
        category: "",
      };
      await Promise.all(
        Object.keys(d).map(async (key) => {
          const property = d[key];
          if (property.type === "people") {
            item[key.toLowerCase()] = property.people
              .map((p) => (p as any).name)
              .join(",");
          } else if (property.type === "rich_text") {
            item[key.toLowerCase()] = property.rich_text[0]?.plain_text;
          } else if (property.type === "files") {
            if (property.files[0]?.type === "external") {
              item[key.toLowerCase()] = property.files[0].name;
            } else {
              let src = property.files[0]?.file?.url;
              if (src && process.env.CLOUD_FLARE_ACCOUNT_ID) {
                const fileName =
                  result.id +
                  "_" +
                  result.last_edited_time +
                  "_" +
                  src.split("/").pop().replace(/\?.*$/, "");
                try {
                  src = await uploadToR2(src, fileName);
                } catch (e) {
                  console.log(e);
                }
              }
              item[key.toLowerCase()] = src;
            }
          } else if (property.type === "title") {
            item[key.toLowerCase()] = property.title[0]?.plain_text;
          } else if (property.type === "checkbox") {
            item[key.toLowerCase()] = property.checkbox;
          } else if (property.type === "multi_select") {
            item[key.toLowerCase()] = property.multi_select?.[0]?.name;
          } else if (property.type === "select") {
            item[key.toLowerCase()] = property.select?.name;
          } else if (property.type === "date") {
            item[key.toLowerCase()] = property.date?.start;
          }
        })
      );
      // console.log(item)
      return {
        content: "",
        data: {
          tags: [],
          title: item.page,
          date: item.date,
          category: item.category,
          writtenBy: item.authors,
          thumbnail: item.thumbnail,
          id: item.id,
          description: item.description,
          status: item.published ? "open" : "draft",
        },
        permalink: `${blogConfig.siteUrl}/${item.category}/${item.slug}`,
        slug: item.slug,
        id: item.id,
        excerpt: "",
        related: [],
      } as Article;
    })
  );

  return posts;
};
utils>notion.tsxの一部

Awesomeで表示されているpagesディレクトリからnotionAPIのコードがある場所まで辿れました🌝

いよいよdescriptionとpeopleをAwesomeに表示させる改造に入ります🔥(準備はいいか!?w

image block

表示させる_description編

これは結構簡単です✌

Awesomeの表示させているpages>index.tsxをもう一度見てみてください 💁‍♀️

returnの前にconsole.log(articles)を追加して確認します👀

image block

articlesを1つずつ取り出してdata.descriptionと記述すれば

NotionDBのdescriptionプロパティを表示させることができます 🌈

実際に記事を表示させるコンポネントは<ArticleCard />コンポネントにまとまっています。

return (
    <Layout>
      <Hero
        title={blogConfig.hero.title}
        description={blogConfig.hero.description}
      />
      <Wrapper>
        <main className="main">
          <ArticleList>
            <Title>{blogConfig.topPage.title}</Title>
            <LatestArticle>
              {articles.map((article) => (
                <AritcleColumn key={article.slug} column={3}>
                  <ArticleCard
                    article={article.data}
                    href={`/${article.data.category}/${article.slug}`}
                  />
pages>index.tsxの一部

ArticleCardコンポネントは components<articles<card.tsxにあります。

components>articles>card.tsxの全コード:

https://github.com/steelydylan/Awesome/blob/master/components/articles/card.tsx

日付の下に<p>{article.description}</p> を入れてみました\(^o^)/

export function ArticleCard({ article, className, href }: Props) {
  // console.log({article})
  return (
    <div className={className}>
      <div className="article-img-wrap">
        <Link href={href}>
          <img
            src={article.thumbnail ?? blogConfig.article.defaultThumbnail}
            className="article-img"
            alt=""
            loading="lazy"
          />
        </Link>
      </div>
      <div className="article-content">
        <TagList
          tags={getTagList(article.tags)}
          category={getCategory(article.category)}
        />
        <h2 className="article-title">
          <Link href={href}>{article.title}</Link>
        </h2>
        <PublishdAt date={article.date} />
        <p>{article.description}</p> 👉これ
      </div>

表示されました\(^o^)/♥\(^o^)/

image block

つなげて表示させる_people編

….これはかなり苦戦しました 🥺(4時間格闘

descriptionで確認したやり方でやってもauthorsの値は空。

そこで、NotionAPIの記述のあるutils>notion.tsxから調査 🔎

utils>notion.tsxの全コード:

https://github.com/steelydylan/Awesome/blob/master/utils/notion.tsx

Authorsという名前のプロパティはNotionAPIでいうとpeopleプロパティを使っています。

https://developers.notion.com/reference/property-object#people

image block

peopleの中身はYoomを使って確認してみました 🤫

image block
🐣
NotionAPIをちょっと確認するのに便利です

PR:

mapで取り出す前に1つだけ取って内容を確認してみます🔎

const posts = await Promise.all(
    results.map(async (result: PageObjectResponse) => {
      const d = result.properties;
      const item = {
        thumbnail: "",
        authors: "",
        slug: "",
        published: "no",
        date: "",
        description: "",
        page: "",
        id: result.id,
        category: "",
      };
      await Promise.all(
        Object.keys(d).map(async (key) => {
          const property = d[key];
          if (property.type === "people") {
            item[key.toLowerCase()] = property.people[0]🚩
              // .map((p) => (p as any).name)🚩
              // .join(",");🚩
          } else if (property.type === "rich_text") {
            item[key.toLowerCase()] = property.rich_text[0]?.plain_text;
          } else if (property.type === "files") {
utiles>notion.tsxのgetDatabase関数の一部

😱😱😱😱😱

image block

name以降が取れていません😱😱😱😱😱

blog.config.tsで設定するidにはこのidを入れてつなげる準備をすることにします✌

writers: [
    {
      id: "148bfa26-a10a-4673-86c7-539868890a5c", 👉これ
      name: "horomi",
      description:
        "Notionサポーターで活動してるけど、独学が生きがいな引きこもりさん",
      image: "/images/profile_500x500.PNG",
blog.config.tsの一部

blog.config(writer)とutils>notion.tsx(writtenBy)ををつなげるために

ulits内に別途get-author.tsというファイルを作りました。

import blogConfig from "@/blog.config";

export const getAuthor = (writtenBy: string) => {
  const author = blogConfig.writers.find((c) => c.id === writtenBy);
  if (!author) {
    return null;
  }
  return author;
};

descriptionを表示させたときと同様にして

components>articles>card.tsxに追記!!

<div className="article-content">
  <TagList
    tags={getTagList(article.tags)}
    category={getCategory(article.category)}
  />
  <p>&#x1f408;&#x200d;&#x2b1b;{getAuthor(article.writtenBy)?.name}</p> 👉追記
  <h2 className="article-title">
    <Link href={href}>{article.title}</Link>
  </h2>
  <PublishdAt date={article.date} />
  <p>{article.description}</p>
</div>
components>articles>card.tsxの一部

できました〜〜〜\(^o^)/♥\(^o^)/♥\(^o^)/

image block

記事のAuthorごとにAuthorカードを切り替えるのも楽しかったです 🥳

image block

おわり

久しぶりに興奮しましたwww

同じNotion blogでも開発者によって全然違う内容なのが面白いなと思いました。

同じTypeScriptなのに…

同じNotionAPIなのに….
同じブログなのに….

Notion blogに対して期待する内容は人それぞれかと思いますが

私はずっと変わりません。

mosyaを始めて4ヶ月目が終わろうとしています。

ただ「おもしろそうだから…」という理由ではじめたmosyaですが、

Awesomeのコードにも通じるものを感じるようになり、

久しぶりに改造を試みたところ

コンポネント同士のつながりを紐解けたり

配列の関数の理解が進んだりと

回り回ってブログの改造力(読解力)が上がったような気がしました。

特に今までなかなか理解できず何度も勉強してきたJavaScriptをmosyaでしっかり整理することができるなんて思ってもいなかったので、本当にやってよかったなという思いでいっぱいです 🥰

まだまだできるようになりたいことがたくさんあるので

少しずつレッスンを進めていこうと思います(*๓´╰╯`๓)♡(*๓´╰╯`๓)♡(*๓´╰╯`๓)♡

PR:


後日談

mosyaのコミュニティに最近できた【宣伝部屋】

作った作品になるかは分かりませんが、記事を投稿してみました✌

image block

Awesomeが急に分かってきたのは、mosyaのおかげなのは気づいていましたが、

ごだいさんのよく使うコードが詰まっているレッスンだったからという発見があり

わくわくしてきました。

mosyaをもっとやればごだいさんの作った数々のプログラムを解読できるようになるのかな…. 🤔

もっと知りたいな〜〜〜〜

Twitterでは更新のお知らせを随時行っています

興味ある方はLet'sフォロー★

▼ この記事に興味があったら同じタグから関連記事をのぞいてみてね

Buy Me A Coffee

新着記事を通知したい??


RSSリーダーにatomのリンクを登録すると通知が行くよ🐌

https://herohoro.com/atom

やってみてね(*´ω`*)(*´ω`*)

Twitter Timeline


フォロー大歓迎\(^o^)/