Misskeyのv2024.9.0リリースから待望の埋め込み機能が使えるようになっていたので、HugoのShortcodeから利用できるようにしてみる


概要

ウェブサイトへの埋め込み | Misskey Hub

Misskeyサーバー上のノートやタイムラインをお持ちのウェブサイトに埋め込むことができます。また、埋め込み先のウェブサイトの見た目に合わせて柔軟にカスタマイズすることもできます。

misskey-hub.net favicon image misskey-hub.net

Misskeyで新しく追加されたウェブサイトへのノート埋め込み機能を、Hugoで利用するための方法を考える。

埋め込みのやり方は以下のコードスニペットを挿入するだけ。

<iframe
    src="https://<HOST>/embed/notes/<NOTE_ID>"
    data-misskey-embed-id="v1_<RANDOM>"
    loading="lazy"
    referrerpolicy="strict-origin-when-cross-origin"
    style="border: none; width: 100%; max-width: 500px; height: 300px; color-scheme: light dark;"
></iframe>
<script defer src="https://<HOST>/embed.js"></script>

ここで、プレースホルダに入れる値はそれぞれ以下の通り。

  • HOST: Misskeyのホスト名。自分の場合はmisskey.4nm1tsu.com
  • NOTE_ID: 該当のノートのID
  • RANDOM: embed.jsで利用するための、同一ページ内で一意なランダム文字列。

misskeyのwebクライアントから特定のノートを指定することで上記埋め込みコードを生成することもできるが、 どちらかというと事前にshortcodeを作成しておいて、

{{< misskey <NOTE_ID> <UUID> >}}

みたいな感じで利用したい。

UUIDを自動生成することも考えたが、

  • seed値として記事の内容をもとに生成→そもそも同一ページ内のUUIDが一致してしまう
  • seed値として時刻をもとに生成→記事のビルド毎に違うUUIDが生成されてしまう(コンテンツに変更を加えていないのにUUIDが変わるのは気持ち悪い)

上記の理由から、以下のキーマップを設定して、UUIDは都度挿入することにした。

参考:(neo)vimでUUIDを生成・挿入するkeymap
nnoremap <leader>uu i<c-r>=trim(system('uuidgen'))<cr><esc>

記事の内容+カウンタ変数を使ってUUIDを自動生成する実装も考えたが、面倒臭くてやめた。

ノートの埋め込み

コード

layouts/shortcodes/misskey.html
{{ $note_id := .Get 0 }}
{{ $uuid := .Get 1 }}
{{ $host := "misskey.4nm1tsu.com" }}

<iframe
  class="misskey-note"
  src="https://{{ $host }}/embed/notes/{{ $note_id }}"
  data-misskey-embed-id="v1_{{ $uuid }}"
  loading="lazy"
  referrerpolicy="strict-origin-when-cross-origin"
  style="border: none; width: 100%; max-width: 500px; height: 300px; color-scheme: light dark;"
></iframe>
<script defer src="https://{{ $host }}/embed.js"></script>
assets/sass/misskey.scss
.misskey-note {
  display: block; /* ブロック要素にすることでmarginを適用 */
  margin: 0 auto 1rem; /* 上下のマージンを指定しつつ中央揃え */
}

(おまけ)タイムラインの埋め込み

タイムラインも同様にして埋め込めるらしいので、Aboutページに以下を入れてみることにした。

Misskey Hubでの説明にある通り、user_idは@から始まるユーザ名とは違うので、「コントロールパネル」→「ユーザー」のRawデータなどから持ってくると良いと思う。

記事中で使うことはないと思うので、こちらに関してはshortcodeは作らない。

コード

index.html
<div class="container index">
  <div class="about-me">
    <img src="https://avatars.githubusercontent.com/u/40907120?v=4">
    <p class="name">4nm1tsu</p>
    <div class="icon-container">
      <a href="https://github.com/4nm1tsu/" target="_blank" rel="noopener noreferrer">
        <ion-icon size="large" name="logo-github" class="icon-highlight"></ion-icon>
      </a>
      <a href="https://misskey.4nm1tsu.com/@4nm1tsu" target="_blank" rel="noopener noreferrer">
        <ion-icon size="large" name="logo-mastodon" class="icon-highlight"></ion-icon>
      </a>
      <a href="mailto:4nm1tsu@4nm1tsu.com">
        <ion-icon size="large" name="mail-outline" class="icon-highlight"></ion-icon>
      </a>
    </div>
  </div>
  <iframe
    src="https://misskey.4nm1tsu.com/embed/user-timeline/9gozgz6f35?maxHeight=450"
    data-misskey-embed-id="v1_951fc0f5-9805-49c2-bea3-9ea1b4c471b8"
    loading="lazy"
    referrerpolicy="strict-origin-when-cross-origin"
    class="timeline"
    >
  </iframe>
</div>
assets/sass/index.scss
...
.about-me img {
  margin-left: auto;
  margin-right: auto;
  border-radius: 50%;
}

p.name {
  text-align: center;
  font-size: 2rem;
}

.about-me .icon-container {
  text-align: center;
  a {
    text-decoration: none;
  }
}

.container .index {
  display: flex;
  justify-content: center;
  align-items: stretch; /* 横並びのとき高さを揃える */
  gap: 20px;
  flex-direction: row; /* 横並びに設定 */
  height: 100%; /* 親要素の高さを100%に */
}

.about-me {
  display: flex;
  flex-direction: column; /* 内容を縦に並べる */
  justify-content: center; /* コンテンツを中央揃え */
  width: auto;
  max-width: 240px; /* 最大幅を設定 */
  padding: 20px; /* パディングを追加 */
  box-sizing: border-box; /* パディングを含むボックスモデル */
  height: 450px;
}

.timeline {
  border: none;
  height: 450px;
  width: 100%;
  max-width: 500px;
  overflow: auto;
  color-scheme: light dark;
  flex: 1; /* 高さを親要素に合わせるためにフレックスプロパティを使用 */
}

/* Responsive adjustments */
@media (max-width: 900px) {
  .container .index {
    flex-direction: column; /* 900px以下で縦並びに変更 */
    align-items: center; /* 縦並びのとき中央寄せ */
    height: auto; /* 縦並び時は自動高さ */
  }

  .about-me, .timeline {
    width: 100%; /* 各要素を幅100%に */
    max-width: 500px; /* 最大幅を設定 */
    text-align: center; /* 中央揃えに */
  }

  .timeline {
    max-height: none;
    flex: none;
  }
}

おわりに

一度作ってしまえば、あとはmisskeyからnote_idだけコピペすればスタイルは適用されるので、 Hugoでノート埋め込み機能を利用する場合はShortcodeを使ったほうが絶対楽だと思う。

参考記事

Insert UUIDs in Vim / Neovim &#8211; Grailbox

www.grailbox.com favicon image www.grailbox.com

Creating a unique id for repeated custom shortcode

Hi all, I have created a custom shortcode to display audio with a waveform using wavesurfer.js. Inefficiencies aside from including the javascript everytime I call the shortcode how can I create a unique identifier for each repeated use of the shortcode in my Markdown? Shortcode

discourse.gohugo.io favicon image discourse.gohugo.io