Counts the Clouds

Gatsbyでブログ構築(3)
2021.06.03

Gatsby
Markdown
tailwindcss

ディレクトリとパスの変更

前:Gatsbyでブログ構築(2)

チュートリアルから発展させてカスタマイズした内容。

記事ページのMarkdownファイルをsrc/postsディレクトリに移動して、サイト上では/posts/<slug>で表示されるようにする。

Markdownファイルの場所を変更するにはgatsby-node.jsslug生成時のbasePathを変更。

表示URLにプレフィックスを入れるのは、node生成時にslugを改変するのが簡単でよさそう。

  exports.onCreateNode = ({ node, getNode, actions }) => {
    const { createNodeField } = actions
    if (node.internal.type === 'MarkdownRemark') {
+     const slug = createFilePath({ node, getNode, basePath: 'posts' })
-     const slug = createFilePath({ node, getNode, basePath: 'pages' })
      createNodeField({
        node,
        name: 'slug',
+       value: `/posts${slug}`,
-       value: slug,
      })
    }
  }

タグを使えるようにする

公式のとおり。

デザインフレームワーク

気になっていたtailwindcssを使ってみる。公式にGatsbyへの導入方法が案内されている。

基本的なタイポグラフィ

はじめはtypography.jsにしようとしたが、head内の読み込み順の関係か、scaleRatioで設定した見出しスタイルがtailwindに上書きされて消えてしまう。

かわりにtailwindcss-typographyを使ってみる。

proseというクラスをつけるとよしなにしてくれるので、これをlayout.jsmain要素に指定。proseクラスにmax-widthが指定されていて、レイアウトが崩れるので少しハマった。

  ...
  const Layout = ({ pageTitle, children }) => {
    ...
    return (
+     <main className="prose">
        ...
      </main>
    )
  }
  export default Layout

カスタマイズの方法が一見よくわからず難儀したが、基本はtailwind.config.jstheme.extend.typography.DEFAULT.cssで上書きできる。デフォルトは https://github.com/tailwindlabs/tailwindcss-typography/blob/master/src/styles.js で設定されている。

画像の扱い

Gatsbyにロックインしてしまうのが気になるので、いったん保留。しばらくは記事内に画像を使わないことにする。

syntax highlighting

書いてあるとおり。

Twilightテーマを使うと文中のcodeの表示が死ぬのでnoInlineHighlight: trueとした。

フォント

日本語の本文は変更しない。英文はGoogle FontsのOverpassがテクニカルな印象で気に入ったので採用。monospaceもOverpass Monoにしたかったが、ウェイトの調整が思い通りにならないのでSource Code Proにした。

Gatsbyでは通常、<body>より上位の構造は隠されているが、.cache/default-html.jsをコピーしてsrc/html.jsに置くと自分でコントロールできるので、Google Fontsの指定タグを追加する。

<html {...props.htmlAttributes}>
  <head>
    <!-- ... -->
    <link rel="preconnect" href="https://fonts.gstatic.com" />
    <link href="https://fonts.googleapis.com/css2?family=Overpass:wght@300&family=Source+Code+Pro&display=swap" rel="stylesheet" />
  </head>
  <!-- ... -->
</html>

CSSのほうはtailwind.config.jsで指定。

const defaultTheme = require('tailwindcss/defaultTheme')
module.exports = {
  theme: {
    fontFamily: {
      'sans': ['Overpass', ...defaultTheme.fontFamily.sans],
      'mono': ['"Source Code Pro"', ...defaultTheme.fontFamily.mono],
    },
  },
}

これだけだと、code highlightingの部分は変わらないので、styles/global.cssでtailwindcssのディレクティブを使ってスタイルを上書き

@tailwind base;
@tailwind components;
@tailwind utilities;
/* ... */
.gatsby-highlight pre,
.gatsby-highlight code,
.gatsby-highlight span {
  @apply font-mono !important;
  @apply font-light !important;
}

もっといい方法があるかもしれないが、とりあえず変更できた。VSCodeのデフォルトのリンターはtailwindcssのディレクティブ記法を許してくれないので、あとでなんとかしたい。

description

meta descriptionを入れる。react-helmetを導入済みなので、meta要素を追加した。

descriptionについてはオプショナルにしたかったが、なにもせずにいきなりクエリでdescriptionを要求するとエラーになる。

 ERROR #85923  GRAPHQL

There was an error in your GraphQL query:

Cannot query field "description" on type "MarkdownRemarkFrontmatter".

とりいそぎ解決したいなら最低1つのエントリーにそのフィールドを追加せよ、とのこと。まあだいたいの記事にdescriptionは必要なので、さしあたってはそれで行く。

- You want to optionally use your field "description" and right now it is not used anywhere. Therefore Gatsby can't
infer the type and add it to the GraphQL schema. A quick fix is to add at least one entry with that field ("dummy
content")

TOCと見出しリンク

gatsby-transformer-remarkを導入済みならば、クエリにtableOfContentsを追加するだけでTOCのHTMLが取れる。DOM決め打ちなのでカスタマイズの範囲は限られる。

  export const query = graphql`
    query($slug: String!) {
      markdownRemark(fields: { slug: { eq: $slug } }) {
        html
        frontmatter {
          title
          description
          date(formatString: "YYYY.MM.DD")
          tags
        }
+       tableOfContents
      }
    }
  `

すでにリンクになっているが、まだ見出し要素のほうにIDが振られていないので動かない。gatsby-remark-autolink-headersを入れて見出しにIDを振る。

% npm install --save gatsby-remark-autolink-headers

書いてあるとおり。gatsby-remark-prismjsを導入しているときは指定順に注意する必要がある。

アンカーリンクで見出しにジャンプするとき固定ヘッダの高さを考慮する

見出しが固定ヘッダの下に突っ込んでしまう。

gatsby-remark-auto-headersのoffsetYというオプションがそれっぽいが、これはいまのところ動かないようだ。何のオフセットなのかもよくわからない。

CSSだけで、このような指定で実現できた。

:target::before {
  content: "";
  display: block;
  height: 40px;
  margin-top: -40px;
}

この方法だと、ターゲットしている見出しだけアイコンが浮いてしまうので、gatsby-remark-autolink-headersのスタイルを上書きして、浮いている分を調整した。

:target a.anchor.before {
  top: 40px !important;
}