Nuxt Content で作ってるブログにある、コードブロックの内容をコピーできるボタンを用意した

Qiita とかを見てると、コードブロックの内容をコピーできるボタンが右上にくっついてることが多い。

けど僕のブログにはない。 よくない。

作ろう。

Override Default Component

https://github.com/nuxt/content/issues/1421#issuecomment-1218167791

./components/content/ 配下にファイルを作成すると、 Nuxt Content で用意されている default の Component を上書きすることができる。

今回は ./components/content/ProseCode.vue を作成した。

まずは雛形を作成

作成するにあたって、 https://github.com/nuxt/content/blob/main/src/runtime/components/Prose/ProseCode.vue の内容をコピーする。

./components/Prose/ProseCode.vue
<template lang="pug">  slot</template><style lang="scss">pre code .line {  display: block;  min-height: 1rem;}</style>

コピーボタンを用意する

コピーボタンを用意するにあたって、準備が必要である。 VueUse を使う。

https://vueuse.org/

ここでは、VueUse の useClipboard を使う

./components/Prose/ProseCode.vue
<template lang="pug">  div.code-block    slot    button(@click="onClick")</template><script lang="ts">import { useClipboard } from '@vueuse/core';const props = defineProps({  code: {    type: String,    default: ''  },})const { copy } = useClipboard();const onClick = () => {  copy(props.code)}</script><style lang="scss">  .code-block {    pre {      padding-top: 2.1111111em !important;      code .line {        display: block;        min-height: 1rem;      }    }  }</s>

これで終わり。

簡単な解説

useClipboard から copy を取得している。

copy は文字通り、コピーをしてくれる関数である。 引数にコピーしたい値を渡すと、クリップボードにコピーしてくれる。

ので、今回は props から受け取った code を渡して、click event でコピーを実行するようにした。

以上。

せっかくなので色々やる

  • ファイル名を表示
  • ファイル名がない場合は、ファイルタイプを表示
  • コピーボタンをホバーしたら、「コピーできるよー」ってテキストを表示
  • コピーが完了したら、終わった旨を表示
./components/Prose/ProseCode.vue
<template lang="pug">div.code-block.relative  span(    v-if="filename"    class="absolute top-0 py-2 px-4 text-xs text-gray-100 bg-zinc-500 dark:bg-gray-800 rounded-br-lg"  ) {{ filename }}  span(    v-else-if="language"    class="absolute top-0 py-2 px-4 text-xs text-gray-100 bg-zinc-500 dark:bg-gray-800 rounded-br-lg"  ) {{ language }}  slot  label(    class="absolute top-0 right-4 normal-case btn btn-ghost rounded-btn hover:text-rose-600  dark:hover:text-sky-300 hover:bg-inherit"    ref='btn'    @click="onClick"  )    span.mr-2(v-if="copied") Copied code!    span.mr-2(v-else-if="isHovered") Copy    font-awesome-icon(icon="copy" v-element-hover="onHover")</template><script setup lang="ts">import { useClipboard } from '@vueuse/core';import { vElementHover } from "@vueuse/components"const props = defineProps({  code: {    type: String,    default: ''  },  language: {    type: String,    default: ''  },  filename: {    type: String,    default: ''  }})const isHovered = ref(false)function onHover(state: boolean) {  isHovered.value = state}const { copy, copied } = useClipboard();const onClick = () => {  copy(props.code)}</script><style lang="scss">  .code-block {    pre {      padding-top: 2.1111111em !important;      code .line {        display: block;        min-height: 1rem;      }    }  }</style>

簡単な解説

vueuse/components の vElementHover を使って、 ホバーしたらうんぬんを実装した。

さらに props に filename や language を追加して、 それらがあったらうんぬんってのも実装した。

Nuxt Content の仕様で、

md
```language{number[]}[filename]// JavaScript のコード```

というのがある

namevalue
languageコードの言語
numberハイライトする行番号 {1,2,3}みたいな感じで指定
span タグに highlight ってクラスがつく
filenameファイル名

って感じです。 なので、今度時間ある時は highlight class に style をつけなくちゃ

yasumemo

Markdown のコードブロックの中で、 ``` をテキストで表示する方法

` 4つで書こうとできます。

ちなみにこれは 5つで囲って、その下に4つ、最後に3つです。

````md
```js
```
````

以上

おわりに

これが今回のコードです。

https://github.com/yanskun/blog/blob/main/components/content/ProseCode.vue