#next-mdx-remote タグの付いた Snippet

markdownページでnext/imageを使う

2021/01/15

import React from 'react';
import Image from 'next/image';

type NextImageProps = {
  src: string;
  alt?: string;
};

export const NextImage: React.FC<NextImageProps> = ({ src, alt, ...props }) => (
  <div
    style={{
      display: 'flex',
      position: 'relative',
      justifyContent: 'center',
      alignItems: 'center',
      width: '100%',
      height: '16em',
      marginBottom: '1.75em',
      backgroundColor: '#f7fafc',
    }}
  >
    <Image {...props} src={src} alt={alt || src} layout="fill" objectFit="contain" />
  </div>
);

markdown で利用する画像サイズは予測しづらいので、next/image の layout="fill" を使い、動的にリクエストを変更してもらう。親コンテナ(のサイズ)が必要になるので、div で wrap しておき、画像自身は objectFit="contain" で枠に収まるように設定した。

import remarkUnwrapImages from 'remark-unwrap-images';

const getDefaultMdxOptions = () => ({
  // ...
  remarkPlugins: [
    // ...
    remarkUnwrapImages,
  ],
});

markdown のデフォルトだと、image をpで囲ってしまい、p -> divの HTML 違反となってしまうため、remark-unwrap-images で p を外す。next-mdx-remote の mdxOptions に remarkUnwrapImages を追加することで対応できる。

references

markdownにカスタムブロックを追加する

2021/01/12

yarn add remark-custom-blocks

remark-custom-blocks を使うと、markdown にカスタムブロックを追加できる。

import remarkCustomBlocks from 'remark-custom-blocks';

const getDefaultMdxOptions = () => ({
  // ...
  remarkPlugins: [
    [
      remarkCustomBlocks,
      {
        exercise: {
          classes: 'exercise',
          title: 'required',
        },
      },
    ],
  ],
});

next-mdx-remote の mdxOptions に remarkCustomBlocks を追加し、オプションを設定する。classes でブロックにあてる CSS クラス名を、title でタイトル部分が必須かどうかを設定できる。

/* 
 * Custom Blocks
 */
.exercise,
.practice {
  border: 1px solid #e2e8f0;
  border-radius: 0.5em;
  margin-bottom: 1.75em;

  .custom-block-heading {
    padding: 0.5em 1em;
    border-radius: 0.5em 0.5em 0 0;
    font-size: 1em;
    font-weight: bold;
  }

  .custom-block-body {
    border-radius: 0 0 0.5em 0.5em;
    padding: 1em;
    font-size: 1em;

    & ol,
    & ul,
    & p {
      margin-bottom: 0;
    }
  }
}

.exercise {
  border-color: #81e6d9;

  .custom-block-heading {
    background-color: #e6fffa;
  }
}

CSS クラス名に対応するスタイルを記述する。今回はブロック全体を角丸矩形で囲い、タイトル部分に背景色を当てた。

/contents/snippet/2021-01-12-remark-custom-blocks/remark-custom-blocks.png
[[exercise | 練習問題 : 三角形の面積を求める]]
| 1. 整数を 1 つ受け取り、その値を 2 倍した値を表示してください
| 2. 整数を 2 つ受け取り、その値の積を表示してください
| 3. 小数を 2 つ受け取り、三角形の面積を求めるプログラムを記述してください
| 4. 問題(3)で、小数点以下は 1 桁で表示するようにしてください

[[name | title]] が開始部分になり、以下 | が続く限りブロックとみなす。| の内部で別の markdown 記法を使っても良い

references

mdxファイルのリンクにtarget=_blankなどを入れる

2021/01/03

import hydrate from 'next-mdx-remote/hydrate';

export const LinkWithTargetBlank = (props) => {
  const { href, ...rest } = props;
  if (href.startsWith('http'))
    return <a href={href} target="_blank" rel="noopener noreferrer" {...rest} />;

  return <Link to={href} {...rest} />;
};

hydrate(content, {
  components: {
    // ...
    a: LinkWithTargetBlank,
  },
});
  • href が外部リンクの場合は、a タグで展開し、target="_blank"rel="noopener noreferrer" を付与する
  • href が内部リンクの場合は、next/link で展開する

Chakra UI の Link が使える場合は、target, ref のかわりに isExternal を付与するだけで OK。

references


Writings

blogsnippetcourse

Contact

Home©︎ suzukalight