イズミログ 2024-11-19T05:47:25.015Z https://github.com/nuxt-community/feed-module イズミログ - フィード Izm51 https://izm51.com/ <![CDATA[Google Cloud認定の初受験で氏名の表記を修正するために焦った話]]> https://izm51.com/posts/google-cloud-certification-name/ 2024-11-19T05:26:46.414Z

初めてGoogle Cloud認定資格の試験を受験しました。

その際、登録した氏名が身分証の表記と異なっていることに試験直前で気づき、受験できない可能性があり焦ってしまいました。しかし、今回受験したテストセンターでは表記が異なっていても受験することができました。

この記事では、サポートへの問い合わせや当日のやり取りを共有し、同じような状況に陥った方の参考になればと思います。

[[toc]]

登録氏名の表記について

Google Cloud認定資格を受験する際、氏名はWebassessorで登録します。
私はこの際、氏名をローマ字表記で登録していました。

しかし、受験登録完了時に送られてくるメールには、次のように記載されています。

CertMetrics に登録されている氏名は、テストセンターにお持ちになる身分証明書と一致している必要があります。

この注意書きを読んで、自分が所持している身分証には漢字表記のものしかなく、登録した氏名と一致していないことに気づきました。 Webassessorに登録した氏名を修正しようとしましたが、WebAssessor上では氏名の修正はできないようになっており、修正にはGoogle Cloud認定のサポートチームへの問い合わせが必要であることが分かりました。

Google認定資格のサポートへの問い合わせ

この問題に気づいたのは、受験当日の寝る前の深夜1時でした。
修正が間に合わない可能性も感じつつ、急いでGoogle Cloud認定のサポートチームに問い合わせました。
https://support.google.com/a/contact/certification

すると、翌朝6時頃にサポートから返信が届いており、以下の情報を提供するよう求められました:

Please provide us with the below details to confirm your identity and update your legal names:

(Registered with Webassessor):
Primary email address:
Address:
Zip code:
Birthday:

To update legal names:

Legal first name:
Legal last name:

これを受け、8時頃に必要な情報を提供して返信しました。
しかし、結果的に氏名が修正されたのは受験終了後の深夜1時頃で、試験には間に合いませんでした。

Google Cloud認定のサポート対応時間は 5 AM to 6 PM PT (日本時間:午後10時〜翌日午前11時) でした。
そのため、この時点で当日中に修正が完了しない可能性が高いと感じ、リスケジュールも検討し始めました。

テストセンターへの問い合わせ

今回の試験はテストセンターでの受験を予約していました。
試験のリスケジュールには費用がかかるため、最終確認としてテストセンターに直接問い合わせてみました。

問い合わせた結果、ローマ字表記と漢字表記の差は問題なく受験可能との回答を得ました。
当日、試験会場では運転免許証とクレジットカードを提示し、本人確認を行ってもらった後、無事に受験することができました。

ただし、この対応はテストセンターによって異なる可能性があります。事前に確認することをお勧めします。
もし受験が認められない場合は、リスケジュールせざるを得ないでしょう。

おわりに

  • 氏名の修正にはサポートへの連絡が必要で、今回は問い合わせから約24時間後に修正されました。
  • ローマ字と漢字の表記違いでも受験できる可能性があるため、緊急時はテストセンターに問い合わせてみましょう。
  • 氏名を身分証と一致させられているか、よくチェックしましょう。

ちなみに今回は、Associate Cloud Engineer (ACE) に無事合格できました。
プロフェッショナルレベルの取得も狙っていきます。

これから受験される方の参考になれば幸いです。

]]>
2024-11-19T05:26:46.414Z
<![CDATA[Fitbitの文字盤を自作して目標歩数までの所要時間を表示してみた!開発者用ブリッジ接続の有効化の備忘も記録]]> https://izm51.com/posts/fitbit-clock-face-time-to-goal/ 2023-05-07T11:37:59.920Z

GWの休日を使って、Fitbitの文字盤(Clock Face)を自作してみました。

文字盤の開発は、HTMLやJSのような文法で、シミュレーターやリファレンスも整備されているので比較的簡単に感じました。
参照した情報をまとめつつ、開発者アカウントの登録や開発者用ブリッジ接続の設定でつまづいたポイントについて書き残します。

[[toc]]

つくったもの

リモートワークで一日に一歩も外に出ない日が平気である生活をしていたのですが、
このままでは不健康まっしぐらと感じたので、最近は意識的に一定の歩数(9000歩)を歩くことを日課にしています。

その日課の継続ができるように、目標達成までの所要時間が予想できるような文字盤作ってみました。

fitbit-time-to-goal-preview

https://gallery.fitbit.com/details/ab76e03b-4b2e-4052-bb1b-2563f2fe9b62

開発の事前準備

以下の記事を参考にしながら開発手順の大枠を掴むことにしました。

  • 「Fitbit Versa 3 / Sense の文字盤を作る - Qiita」
    https://qiita.com/ChiiAyano/items/17fe390e00c292514350

しかし、記事内で触れられている "Fitbit Studio" は April 20, 2023 にクローズされており、一部手順が異なっていました。以下、2023/5月時点での自分が実施した準備作業の備忘録を残します。

前提状況

今回の開発を始める前の自分の状態は以下です。

  • Fitbitのアカウント(利用者として普通に使うためのアカウント)は作成済み
  • Fitbitのアプリ(自分の場合はAndroidアプリ)がインストール済み・ログイン済み
  • アプリとFitbitデバイスの紐付け済み

開発者アカウントの登録手順

FitbitのDeveloperサイトのガイド"Getting Started"の手順を参考に進めます。
https://dev.fitbit.com/getting-started/

このガイドには説明がなかったですが、開発をすすめるためには自分のFitbitアカウントを開発者アカウントとして登録しておく必要がありました。

上部のメニューバーから開発者向けページを開くと、アカウントが未登録の場合「enroll」のボタンが表示されました。
fitbit-create-developer-account

このとき、"Register An App"と"Gallery App Manager"の2つのリンクがあり、どちらも開発者向けページですが、自分の場合は"Gallery App Manager"の方で「enroll」ボタンを押すまでFitbitシミュレーター等がうまく動作しませんでした。(You must be enrolled as a developer to use this application.というエラーメッセージが出た。)

"Register An App"の方でログイン等しても開発者アカウントのenrollとはならないようです。
(Clock Face の作成にあたってはこちらのページでの操作は特に必要なさそうでした。)

ローカル開発環境の準備

ローカル環境構築は、ガイドの通り進めることができました。
https://dev.fitbit.com/getting-started/

概要

  • node.js のインストール (自分は元から完了済み)
  • Fitbitシミュレータのインストール (自分はmac版をインストール)
  • プロジェクトの作成 (コマンド: npx create-fitbit-app my-first-clock )
  • シミュレーターでの動作確認 (npx fitbit でfitbitのCLIに入ってから bi コマンド)

実機での動作確認手順

実機での動作確認方法も"Getting Started"のガイド内に記載があります。

If you're using a Fitbit device, you need to enable the Developer Bridge. On the watch, go to Settings and tap Developer Bridge, then wait until it says Connected to Server.

Developer Bridge(開発者用ブリッジ接続)の有効化には2つの操作が必要でした。

  • スマホアプリでの"開発者用ブリッジ接続"の有効化
    • Androidアプリの場合: 左上の丸いプロフィールアイコンをタップ→自分の端末("Versa 3"など)をタップ→"開発者メニュー"→"開発者用ブリッジ接続"のトグルを有効化
  • Fitbitデバイスでの"開発者用ブリッジ接続"の有効化
    • 設定を開く→"開発者用ブリッジ接続"("Versa 3について"と"シャットダウン"の間に表示されました)→トグルを有効化

また、これらのボタンが表示されるようにするためには、前述の開発者アカウントの登録が先に必要でした。 開発者アカウントの登録ができたあと、アプリからログアウトして再ログインすることでボタンが表示されるようになりました。

※ 参考にした記事: Fitbit Ionic の設定画面に "開発者向けメニュー" を出す方法 - Qiita

ちなみに"開発者用ブリッジ接続"を有効にしても、開発していると十数分ごとくらいで接続が切れてしまい、都度再有効化する必要がありました…。

アプリとFitbitデバイスの両方で開発者用ブリッジ接続を有効にした状態で、fitbitのCLIに bi もしくは install を入力すると、Fitbitデバイスに開発中の文字盤がインストールされて動作確認ができました。

開発で参考にしたリファレンス

ロジック関連

  • 日時の表示
    https://dev.fitbit.com/build/reference/device-api/clock/
  • 歩数等の取得
    https://dev.fitbit.com/build/reference/device-api/user-activity/

表示関連

  • SVG: WebでいうHTMLのような構造構築関連 (いわゆるベクターを書くようなものではなかった)
    https://dev.fitbit.com/build/guides/user-interface/svg/
  • CSS: Styling関連
    https://dev.fitbit.com/build/guides/user-interface/css/
  • Javascript: Domの操作関連
    https://dev.fitbit.com/build/guides/user-interface/javascript/

文字盤の公開方法

Gallery App Manager からビルドしたファイルアップロードや説明項目の登録ができました。
https://gam.fitbit.com/apps

手順は最初にも紹介した下記の記事が参考になりました。

  • 「Fitbit Versa 3 / Sense の文字盤を作る - Qiita」
    https://qiita.com/ChiiAyano/items/17fe390e00c292514350

項目を入力すると審査に提出することができ、審査を通れば一般に公開することができるようです。

感想

環境構築(というよりも開発者用ブリッジ接続の有効化周り)で少し苦戦しましたが、文字盤の作成自体はとても簡単で、また違う用途の文字盤やアプリを作ってみたいと思いました。

APIドキュメントをみると、FetchやPOSTができるメソッドも用意されているようなので、いろいろなことができそうです。
https://dev.fitbit.com/build/reference/companion-api/fetch/

最近、M5StickCやラズパイも調達したので、組み合わせてなにか面白いことできないかなーと考え中です。この記事はここまで、ではまた〜!

]]>
2023-05-07T11:37:59.920Z
<![CDATA[P5.jsでAudio Visualizerを作ってみた!【ビート検知】]]> https://izm51.com/posts/p5-js-audio-visualizer/ 2020-06-20T23:15:24.017Z

こんにちは。
今回はP5.jsをつかってサウンドビジュアライザーを作成してみました。

P5.jsは、プログラミングで絵を描くためによく使われているProcessingという言語のJavaScript版ライブラリになります。
以前からビジュアライザーを作りに興味はあったのですが、今回はコチラの記事

Adobe製品を使わない"デザイナー"?「ビジュアルコーダー」が考える、自己満足で終わらないWebデザインとは

に触発されまして、Web上にビジュアライザーを作れたら面白いと思いやってみました!!

P5.jsはオーディオを扱うにも便利ですが、ビートの検知で苦労したところがありました。
かなり荒い調整なので参考になるかどうかはわかりませんが、簡単に記事に残しておこうと思います。

[[toc]]

作ったもの

Web版

イメージ画像

pastel-visualizer

https://izm51.github.io/visual-coding/visualizer1-pastel/

※ブラウザの設定でマイクを許可し、画面をクリックすると開始します。

YouTube Demo

デモ動画

背景はパステルカラーがくるくると回っていて、スネア(の音域)に合わせて色が変わります。
そしてキックに合わせて中央の丸が大きくなり、そこから円や四角が近づいてくるようになっています。
下辺にはスペクトラムも設置しました。

始めは何となくで決めた色でしたが、パステルカラーとホワイトのおかげでKawaii感じになりました。

Beat Detection の実装

P5.jsには描画だけでなく、Audioに関する便利な関数もたくさんありました。
おかげでマイクの取得やfftなどは非常に簡単でした!

しかしビートの検知には若干苦労しました。
P5.js自体にもPeakDetectという関数があったのですが、ちょっと反応がとがりすぎという印象でした。
(触り始めのときの感想なので、チューニング次第では普通に使えるかも?)

そこで今回は、下記記事を参考に簡単なBeatDetectorも実装してみました。

https://www.airtightinteractive.com/2013/10/making-audio-reactive-visuals/

※テンポを計算するものではなく、ある周波数領域の音量が大きくなったのを検知するものです。

class BeatDetect {
  constructor(mode = 'kick', freq2) {
    if (!isNaN(freq2) && !isNaN(mode)) {
      this.freq1 = mode;
      this.freq2 = freq2;
    } else {
      if (mode == 'snare') {
        this.freq1 = 2000;
        this.freq2 = 6000;
      } else if (mode == 'male') {
        this.freq1 = 200;
        this.freq2 = 2000;
      } else {
        // mode == "kick"
        this.freq1 = 20;
        this.freq2 = 80;
      }
    }

    this.time = 0;
    this.threshold = 0;
    this.minThreshold = 0;

    this.decayRate = 0.01;
    this.minThresholdRate = 0.8;

    this.holdTime = 45;
    this.marginThresholdTime = 10;
    this.marginThreshold = 0.06;
  }
  update(fft) {
    const e = fft.getEnergy(this.freq1, this.freq2);
    const level = e / 255.0 || 0.0;
    let isBeat = false;
    if (level > this.threshold && level > this.minThreshold) {
      this.threshold = level * 1.05;
      this.minThreshold = max(this.minThreshold, level * this.minThresholdRate);
      if (this.time > this.marginThresholdTime) {
        isBeat = true;
      }
      this.time = 0;
    } else {
      if (this.time == this.marginThresholdTime) {
        this.threshold -= this.marginThreshold;
      }
      this.time += 1;
      if (this.time > this.holdTime) {
        this.threshold -= this.decayRate;
      }
    }
    return { threshold: this.threshold, level: level, isBeat: isBeat };
  }
}

全体のコードはGitHubにあります。

課題としては、

  • 反応の良い周波数帯を探る
  • 一つの音に何回も反応させたくない(短時間で反応しすぎるのを防ぐ)
  • 逆にアクセントの強弱で弱くなってるキック等にはちゃんと反応させたい

という感じでした。

キックとスネアを検知する

まずは曲のリズムに良い感じに反応する周波数帯を探しました。

自分がよく聞くのはMathRock(バンド系)とFutureBounce(クラブ系)、あとはアイドル系です。
なので、今回はその3ジャンルで探りました。

ビートを取るためであれば低音域が最適かと思っていましたが、キックにメロディがかぶりまくることもあれば、低音域で全く音が鳴っていないこともあり、低音だけでは絵の変化に面白みがないパターンがありました。
いろいろ試した結果、バスドラの音域(20Hz~80Hz)とスネアやクラップらへんの音域(2000Hz~6000Hz)が曲への反応がよさそうだったので、この2領域を使うことにしてみました。

ビートが連続で検知されまくるのを防ぐ

次に、一回のバスドラで何回もビートが検知されたり、曲が静かになって音量に変化がない時に連続で反応してしまうことがあり、そこに対処しました。

beat-detect-visualizer

threshold等の変数調整時につかっていたデモ

始めはthreshold、decayRate、holdTimeの変数だけでちょうどいい調整を探していたのですが、曲によってどうにも反応が変わってしまい、いろいろと手探りで変数を増やしました。
具体的には下記の部分になります。

    if (level > this.threshold && level > this.minThreshold) {
      this.threshold = level * 1.05;
      this.minThreshold = max(this.minThreshold, level * this.minThresholdRate);
      if (this.time > this.marginThresholdTime) {
        isBeat = true;
      }

if (this.time > this.marginThresholdTime)
で連続の検知を防止し、

this.minThreshold = max(this.minThreshold, level * this.minThresholdRate);
で曲中の静かな部分ではビートを検知しすぎないようにしました。

強弱のあるキックにもうまく反応させる

今回のビート検知の仕組みでは少し前に鳴った音量がビート検知の閾値になるため、例えばバンド系の曲でバスドラがダブルで踏まれているときに、二つ目が少し弱かったりすると反応が悪くなってしまいました。

そこで、無理やり感はありますがビート検知から少し時間が経過したら、holdTimeより少し早いタイミングでthresholdを少しだけガクッと下げるようにしました。

      if (this.time == this.marginThresholdTime) {
        this.threshold -= this.marginThreshold;
      } // this.marginThreshold = 0.06

なにかもっとちゃんとしたチューニングはありそうですが、今回はいい感じの反応になったので一旦これで満足しています。

まとめ

という訳で、今回は初めてのビジュアライザーを作成してみました。
思い返せば中学生くらいの頃から音に合わせて動くプロジェクションマッピングとか、高校時代もインスタレーションに興味がありましたがなんだか手が出せずにいました。

少しずつWebやオーディオの知識をためてきたおかげで、気づいたら昔憧れていた領域に手を出せるようになっていました。

Processingなら気軽にビジュアルコーディングができます!
今後もまた面白いものを作っていきたいと思います。

ではまた。

]]>
2020-06-20T23:15:24.017Z
<![CDATA[Nuxt + Contentful のブログにFeedを追加する方法【Markdown対応】]]> https://izm51.com/posts/nuxt-contentful-blog-feed/ 2020-05-04T02:06:50.501Z

最近InoreaderというRSSリーダーで情報収集をするようになり、自分のブログもフィードに対応させたいと思うようになりました。
そこでこの記事では、"@nuxtjs/feed"を使ってブログの更新情報をフィードで提供する手順を紹介します。

[[toc]]

使用するプラグインのインストール

まず、今回使用するプラグイン @nuxtjs/feedをインストールします。

$ npm install @nuxtjs/feed

nuxt.config.jsのmodulesに追加します。

modules: [
    '@nuxtjs/feed' // 追加
],

そして、nuxt.config.jsにfeedの設定を記入するセクションを追加します。

modules: [
    '@nuxtjs/feed'
],
// ここから追加
feed: [
  //  この中に設定を記述していく
]

Feedの設定

Contentfulから記事一覧を取得するために、~/plugins/contentfulを読み込みます。
nuxt.config.jsの最初のほうに次の行を追加します。

const client = require("./plugins/contentful");

feedの設定項目を記述していきます。

まず、フィードを書きだすURLを相対パスで設定します。
一般的には、"/feed", "/feed/", "/feed.xml"などが多いようです。

feed: [
  {
    path: '/feed' // 追加
  }
]

次に、フィードに記事の一覧が登録されるように設定していきます。
当ブログの設定を例として紹介しますので、適宜書き換えて参考にしてください!

feed: [
  {
    path: '/feed',
    // ここから追加
    async create(feed) {
      feed.options = {
        title: "イズミログ",
        link: "https://izm51.com/feed", // 上のpathで設定したものと対応するように
        description: "イズミログ - フィード"
      };
      // 記事を取得
      await client
        .getEntries({
          content_type: "post",
          order: "-sys.createdAt"
        })
        .then(entries => {
          entries.items.forEach(post => {
            feed.addItem({
              title: post.fields.title,
              id: `https://izm51.com/posts/${post.fields.slug}/`, // 記事のURL
              link: `https://izm51.com/posts/${post.fields.slug}/`, // 記事のURL
              description: post.fields.description,
              content: post.fields.content,
              date: post.fields.update ? new Date(post.fields.update) : new Date(post.sys.createdAt), // 記事の最終更新日
              published: new Date(post.sys.createdAt), // 記事の公開日
            });
          });
          feed.addCategory("blog");
          feed.addContributor({
            name: "Izm51",
            link: "https://izm51.com/"
          });
        });
    },
  }
]

dateについて補足しますと、このブログではContentfulのContent modelにupdateという日付型の入力欄を設置し、記事を修正したときに手動で書き換える形式にしています。
ちょっとした修正だけで毎回最終更新日を更新したくないため、このようにしています。

最後に、cacheTimeとフィードのタイプを設定します。

feed: [
  {
    path: '/feed',
    async create(feed) { /* 略 */ },
    // ここから追加
    cacheTime: 1000 * 60 * 15,
    type: "atom1"
  }
]

フィードのタイプは"rss2", "atom1", "json1"の3種類が設定できます。
これらのタイプとはフィードの規格のことですが、"rss2"か"atom1"に設定しておけばたいていのRSSリーダに対応しているかと思います。

MarkdownをHTMLに展開する

ここまでで一応フィードの設定は完了ですが、このままでは記事の内容がMarkdown形式のまま配信されてしまいます。
そこで、markdown-itで記事内容ををHTML形式に展開してから登録するように設定していきます。

nuxt.config.jsの最初の方に次の一行を追加して、markdown-itを読み込みます。

import MarkdownIt from 'markdown-it';

feedのcreateの中で、markdown-itを使用するための準備をしておきます。

    async create(feed) {
      feed.options = {
        // 略
      };
          
      // 追加
      const md = new MarkdownIt({
        html: true,
        typography: true,
      })

feed.addItemの部分で、記事の内容をmarkdown-itでHTMLにレンダリングしたものをcontentに登録するように設定します。

            feed.addItem({
              // 略
              content: md.render(post.fields.content), // 変更

記事内にある画像とは別にサムネイル画像を設定している場合は、このように記事の最初に画像を挿入してしまうのもおすすめです。

content: `<img src="https:${post.fields.image.fields.file.url}?w=1080">` + md.render(post.fields.content),

まとめ

最終的な完成版は次のようになりました。

feed: [
  {
    path: '/feed',
    async create(feed) {
      feed.options = {
        title: "イズミログ",
        link: "https://izm51.com/feed",
        description: "イズミログ - フィード"
      };
          
      const md = new MarkdownIt({
        html: true,
        typography: true,
      })
      
      await client
        .getEntries({
          content_type: "post",
          order: "-sys.createdAt"
        })
        .then(entries => {
          entries.items.forEach(post => {
            feed.addItem({
              title: post.fields.title,
              id: `https://izm51.com/posts/${post.fields.slug}/`,
              link: `https://izm51.com/posts/${post.fields.slug}/`,
              description: post.fields.description,
              content: `<img src="https:${post.fields.image.fields.file.url}?w=1080">` + md.render(post.fields.content),
              date: post.fields.update ? new Date(post.fields.update) : new Date(post.sys.createdAt),
              published: new Date(post.sys.createdAt),
            });
          });
          feed.addCategory("blog");
          feed.addContributor({
            name: "Izm51",
            link: "https://izm51.com/"
          });
        });
    },
    cacheTime: 1000 * 60 * 15,
    type: "atom1"
  }
]

$ npm run generateすることでフィードが生成されるようにできました!
あとはトップページなどにフィードへのリンクを追加すれば設定完了です。

これで、普段使用しているRSSリーダーでも自分のブログが見られるようになりました!
https://izm51.com/feed

ではまた。


【参考】
generate時にエラーが出たときの対処
javascript - TypeError: Cannot add module namespace property '_nuxtConfigFile' to nuxt.config.js with NUXT 2.4.5 - Stack Overflow

nuxt.config.jsmodule.exports = {}export default { } に変更する

]]>
2020-05-04T02:06:50.501Z
<![CDATA[Googleフォトのアルバムから埋め込みコードを生成するツールを作った【ブログに便利】]]> https://izm51.com/posts/google-photos-embed-link-generator/ 2020-04-02T11:54:54.677Z

こんにちは、イズミです。

今回は、Googleフォトのアルバム共有リンクから、アルバムに含まれる画像の埋め込み用タグを一気に生成するツールを作成しました。

リンク:Google Photos Embed Link Generator

この記事には、このツールの使い方と、作成時に参考にしたことなどを残しておきます。

[[toc]]

Googleフォトから埋め込みコードを生成したい理由

このブログでは、ブログ記事の管理に Contentful を使用しています。
Contentfulは、 無料プランの場合に保存できるレコード数が5000まで という制限があります。
※レコード数は、記事などの"エントリー数"と、アップロードした画像などの"アセット数"の合計

そこで本ブログではレコード数を節約するため、 画像サーバーとしてGoogleフォト を使用しています。
(過去記事:ブログの画像サーバとしてGoogleフォトを使う

しかし、この過去記事で紹介した方法では画像一枚一枚に手間がかかってしまい面倒になったため、アルバムから一気に 埋め込み用コードを生成するWebツール を作成してみました。

アルバムの作成手順と埋め込みコード生成の仕方

使い方はいたって簡単で、Googleフォト上でアルバムを作成し、その共有URLを張り付けるだけです。

アルバムの作成方法から、実際に手順を追って説明していきます。


まず、ブログに使用したい画像たちをGoogleフォトにアップロードします


アップロードが完了すると、左下にモーダルが出現します。
ここで、「アルバムに追加」のボタンを押して、先ほどアップロードした画像たちのアルバムを作成します。
(「共有アルバム」のボタンを押すと手順を若干飛ばせます。お好みで)


「新しいアルバム」を押してアルバムを作成します。
既存のアルバムに追加しても問題ないです。


タイトルを適当に入力し、左上の☑ボタンを押します。


右上の共有ボタンを押します。


「リンクを作成」ボタンを押します。


少し待つと共有用リンクが作成されるので、それをコピーします。


Google Photos Embed Link Generator を開きます。
入力欄に先ほどコピーしたアルバムの共有リンクを張り付けて、「GENERATE」ボタンを押します。
(リンクのURLではなく、https://photos.app.goo.gl/ 以後のIDのみ張り付けても動作します。)


するとこのようにアルバム内の画像一覧が表示されます。


オプション欄で次のような設定をできるようにしています。

  • Width:Googleフォトから取得する画像の横幅を指定できます。
  • Markdown:有効にするとマークダウンで画像を挿入するためのシンタックスを自動で追加します。


画像自体をクリックするか、各画像の右下の「Copy!」ボタンを押すと、埋め込みコードがクリップボードにコピーされます。
これをブログ編集画面等の埋め込みたい箇所に張り付ければ完了です!

埋め込みコード作成後の画面はそのままブックマークしておいて、作業を中断してまた別のタイミングで開くこともできます。

https://google-photos-embed-generator.glitch.me/***
の***の部分にアルバムのIDを入力して直接開くことも可能です。

※利用上の注意

  • アルバムの共有を無効にしてしまうと、ブログに張り付けた画像も表示できなくなると思います。
  • 本ツールによる画像の流出などについて責任は持てません。ブログ等でパブリックに公開する用の画像のみで利用してください。

参考記事

今回のツール作成では、以下の記事を大いに参考にしました。
How I used Google Photos to host my website picture gallery

Googleフォトのアルバムから貼り付け用のURLを取得するところまでは上の記事の内容をそのまま使用しています。
この記事のサンプルでは画像の一覧をjsonのようにただ並べて取得するだけだったので、ブログ作成に利用しやすいようにアレンジしてみました。

今回はexpressで作成しましたが、慣れていなかったのでたぶん簡単そうなところでもつまずいてしまいました。

まとめ

最後に、今回作成したツールのソースコードを一応貼っておきます。
リンク:Glitch

そもそも根幹部分は僕の製作ではないですが、ご自由に参考にしてください!

もし使ってみて感想や要望があれば、ぜひコメント欄まで!!

あと最近、東京の隠れフォトスポットを探すブログを始めたので、興味のある方は見てみてください!
Tokyizm - 「ココで撮りたい」を見つけるWebメディア -

ではまたー!

]]>
2020-04-02T11:54:54.677Z
<![CDATA[国際学会に初参加した感想と観光の写真【大阪】]]> https://izm51.com/posts/osaka-photo-Oct-2019/ 2019-10-29T23:44:12.551Z

10/15~18に大阪で開催された国際会議 “2019 IEEE 8th GCCE” でポスター発表してきました。
今回はそのあっさり目の感想と観光の写真を記事にしたいと思います。

初めての学会参加で感じたこと

今回の学会参加を通して僕は、学会とは “情報交換の場” だと感じました。
(経験者の方々にとってはすごく当然のことだと思いますが。)

学会初参加の僕にとって、学会は雰囲気の想像できない未知の場所で不安もありました。上手く発表できるのか、英語の質疑に対応できるのか、など心配事も多かったです。

実際に参加してみると、今回僕は「ポスター発表」だったこともあり、“発表”というよりは “コミュニケーション” という感じで、あまり緊張はなかったです。会話を通して自分の研究内容を知ってもらい、様々な視点から意見をもらうことができました。

ポスター発表のよさ

今回の学会では、「口頭発表」、「ポスター発表」、「デモ発表」の3種類の発表形式がありました。

「口頭発表」は会議室のような部屋の前にスライドを表示して発表する “The学会”感のある形式、「ポスター発表」は研究内容をまとめたポスターの前に立ち、興味を持ってくれた人に説明する形式、「デモ発表」はポスターに加えてPCやハードウェアを持参し、実際にデモが行える形式です。

「口頭発表」は発表15分+質疑5分でしたが、「ポスター」「デモ」は1時間40分の長い発表時間がありました。この 長い時間で色々な人と意見交換ができる ことは、「ポスター発表」形式の良い点だと感じました。今回は専門の近い人だけでなく、分野の異なる人にも発表を聞いてもらうことができたので、専門的な意見だけでなく素朴な疑問や感想もいただくことができました。

まとめ

学会期間中には観光のバスツアーやヒルトンホテルでの夕食会のようなイベントもあり、全体を通して とても楽しかった です。刺激ばかりで、今後のモチベーションにもつながる良い経験となりました。


ここからは大阪観光の写真。
2日目の夜に開催されたバスツアーでは、夜の大阪城と梅田スカイビルを観光しました。

梅田スカイビル展望台からの景色。

梅田スカイビル・屋上の空中庭園展望台からの下りエスカレーター。

梅田スカイビル(下から)

夜の大阪駅。蔦屋書店が大きくて便利そう。

大阪駅内で撮影。良いカーブ。

大阪駅から宿までの帰り道で撮影。

最終日は発表と閉会式の後、通天閣など大阪の名所を巡り、グルメも堪能。

学会も観光も非常に有意義な大阪旅でした。
海外で開催の学会にも挑戦できるように頑張りたい。

この投稿をInstagramで見る

Tatsuhiko Imaizumi(@mimizm51)がシェアした投稿 -

]]>
2019-10-29T23:44:12.551Z
<![CDATA[スマホのブラウザに最適なミニマルなブックマークリストサイトを作った]]> https://izm51.com/posts/the-homepage/ 2019-09-24T02:38:05.735Z

今回は、スマホ版ブラウザのホームページに使えそうな、シンプルなブックマークリストサイトを作ってみました。

ログイン不要で、自由に設定したブックマークリストを表示できます。
見た目はダークでミニマル。落ち着いたデザインを目指しました。

リンク: https://izm51.github.io/home/

Preview

[[toc]]

仕様

  • サイト上でブックマークの追加・削除ができる。
  • ブックマークリストを更新するとURLのクエリが変更される。
  • リストが完成したら、そのURLをホームに設定する。
  • ログインやCookie情報が不要で誰でも利用できる!

使い方

  • 最下部のOptionからブックマークを追加
    • タイトル未入力の場合はURLがタイトルになる
  • 各リンク右端のバツボタンでリストから消去
  • 編集完了後のURLをブラウザのホームに設定

経緯

僕はAndroidでChromeを使っています。

Android版Chromeでは、新しいタブを開くとChromeが自動で判断した「よく使うサイト」と「おすすめの記事」が表示されます。
しかしこの「新しいタブ」ページはカスタマイズができず、「よく使うサイト」も自由に設定することができませんでした。

僕はシンプルにブックマークさえ表示できればよかったので、それができるサイトを探しましたが見つかりませんでした。(どこかには絶対あると思うが)

というわけで探すより作ってしまった方が早いと思ったので、今回はシンプルなブックマークリストサイトを作ってみました。

しかし結果として、新しいタブに表示することはできませんでした。
このサイトをChromeのホームページに設定することで新しいタブを開いた際に表示されるページを変更できると思っていました。
しかし、ホームページを変更しても新しいタブページは変更されませんでした(泣)
ホームページのデフォルトはchrome://newtab/でしたが、ホームページ=新しいタブで表示されるページ というわけではありませんでした。

せっかく作成したので、Chromeのホームボタンから飛べるブックマークリストとして使うことにしました。
Chromeのブックマークは表示するまでに2回タップ操作(メニューボタン→ブックマーク)が必要だったので、それが1回に短縮できて少し便利になりました。

プログラム

リポジトリ: https://github.com/izm51/home

シンプルにHTMLと素のJavascriptのみ。
(スタイルはSCSSで書いてます。)

以下作成時のメモを記録します。

アイコンの取得

faviconを取得するGoogleのAPIを使用しました。

<img src="http://www.google.com/s2/favicons?domain=[URL]">

http://www.google.com/s2/favicons?domain=[URL][URL] にアイコンを取得したいサイトのURLを指定するだけで画像を取得できます。

しかし、サイズが16x16で非常に小さいのが難点です。
touch iconなどを取得できる方法はあるんでしょうか。探し中です

クエリの取得

今回のサイトでは、ブックマークのリストをクエリにしてURL内に保管しています。
クエリは ?[サイト名]=[URL]&[サイト名]=[URL]... という形にしています。

素のJavascriptでのクエリの取得は初だったので、以下を参考にしました。
参考: JavaScriptでURLクエリを取得する - Qiita

参考記事内では

var queryArr = queryStr.split('=');
queries[queryArr[0]] = queryArr[1];

という形でkeyとvalueを分けていましたが、今回のvalueとなるURLには = が含まれる場合もあるので以下のように変更しました。(14,15行目)

//クエリの取得
function getUrlQueries() {
  var queryStr = window.location.search.slice(1);  // 文頭?を除外
      queries = {};

  // クエリがない場合は空のオブジェクトを返す
  if (!queryStr) {
    return queries;
  }

  // クエリ文字列を & で分割して処理
  queryStr.split('&').forEach(function(queryStr) {
    // = で分割してkey,valueをオブジェクトに格納
    var eqIndex = queryStr.indexOf('=')
    queries[queryStr.slice(0, eqIndex)] = queryStr.slice(eqIndex+1)
  });

  return queries;
}

リンクの作成(DOM操作)

クエリから取得したブックマークのリストをもとにリンクを作成します。

今回はひたすらに要素を追加していくだけです。
一気に複数の要素を追加する際は、一度 DocumentFragment に集めた後で追加することでパフォーマンスが向上するようです。

参考: もうjQueryには頼らない!素のJavaScriptでDOMを操作するための基礎知識 - WPJ

<body>
  <div id="wrap"></div>
</body>
const pages = getUrlQueries()

const wrap = document.getElementById('wrap')
const fragment = document.createDocumentFragment()

for (const k in pages) {
  const page = pages[k]

  const box = document.createElement('div')
  box.setAttribute('class', 'link-box')

  const a = document.createElement('a')
  a.setAttribute('class', 'link-button')
  a.setAttribute('href', page)

  const img = document.createElement('img')
  img.setAttribute('src', 'http://www.google.com/s2/favicons?domain='+page)
  const p = document.createElement('p')
  p.textContent = decodeURI(k)

  const btn = document.createElement('button')
  btn.setAttribute('class', 'remove-button')
  btn.setAttribute('onclick', 'removeQuery("'+decodeURI(k)+'")')
  btn.textContent = 'X'

  a.appendChild(img)
  a.appendChild(p)

  box.appendChild(a)
  box.appendChild(btn)
  fragment.appendChild(box)
}

wrap.appendChild(fragment)

リストの更新

ブックマーク追加の場合は、入力欄の内容をクエリに追加し、URLへ移動します。
逆に削除の場合は、バツを押されたキーをクエリから消去し、URLへ移動します。

ブックマークの追加

<input type="text" name="title" id="title">
<input type="text" name="url" id="url">
function addQuery() {
  const queries = getUrlQueries()

  const url = document.getElementById('url').value
  let title = document.getElementById('title').value
  if (title == "") {
    title = url
    title = title.replace(/=/g, "")
  }

  if (title!=""&url!="") {
    queries[title] = url
    updateParams(queries)
  }
}

ブックマークの削除

<div class="link-box">
  <a class="link-button" href="https://izm51.com/">
    <img src="http://www.google.com/s2/favicons?domain=https://izm51.com/">
    <p>イズミログ</p>
  </a>
  <button class="remove-button" onclick="removeQuery(&quot;イズミログ&quot;)">X</button>
</div>
function removeQuery(q) {
  if (window.confirm(q+' のリンクをリストから消去しますか?')) {
    const queries = getUrlQueries()

    delete queries[encodeURI(q)]

    updateParams(queries)
  }
}

ページの更新(URLの更新)
参考: Javascriptでパラメータを取得したり設定したりする | webの覚え書き

function updateParams(queries) {
  let setParam = '?'
  for (k in queries) {
    setParam = setParam + k + '=' + queries[k] + '&'
  }
  setParam = setParam.slice(0, -1)

  location.search = setParam
}

その他参考

まとめ

今回は、シンプルなブックマークリストサイトを作ってみました!

リンク: https://izm51.github.io/home/
リポジトリ: https://github.com/izm51/home

機能としては単純ですが、自分好みの最小構成で作れたので良かったです。

新しいタブに表示できなかったのは残念ですが、ブックマークが少し便利になりました。
もしよければ誰でもご自由にご利用ください!

ではまた。

]]>
2019-09-24T02:38:05.735Z
<![CDATA[英会話の練習を始めようと思う話 - DMM英会話体験談]]> https://izm51.com/posts/eikaiwa-hajimeru-story/ 2019-08-17T17:02:30.741Z

勉強やプログラミングで困ったときに英語の情報しかないことは多々あります。
そして僕は海外のEDMやドラマ・ゲームも好きなので、そのクリエイターへのインタビューやメイキングストーリーなどを楽しむにも英語力が必要です。

これらを理解できるようになるだけでなく、せっかくなら英語でコミュニケーションできるようになりたい!
というわけで前々から考えていた英会話学習を本格的に始めることにしました!

[[toc]]

勉強方法

勉強方法は、僕の大好きなバンド"PENs+"のボーカル新井リオさんが昔から発信している英語勉強法を実践することにします。
独学3年間の努力と道のり。日本で英語が話せるようになった僕の勉強法

【勉強法】

①英語日記を書く
時間を決めて書く(15分間)
分からない単語は調べてとりあえず書いてみる

②オンライン英会話で添削してもらう
自然な表現に直してもらう

③添削してもらった日記を暗唱できるまで繰り返し練習する 読み上げ機能を使ってシャドーイングする

英語日記の書き方はYouTubeチャンネル"Hapa 英会話"さんの方法も参考にすることにします。
着実に英会話力を伸ばす学習法「Journaling」【#106】

英語日記は1週間前から書き始めていて、privateなinstagramアカウントに投稿しています。

instagram-english-journaling

日本語で3行程度の日記を書き、これを基に英文を作成してます。
単純に日記として毎日を振り返ること自体が結構楽しいです。

継続のために

これもリオさんの継続のコツを参考にします。

僕が英語勉強を【5年間継続】させた、3つの方法とコツ【勉強が続かない人へ】

①【理由】を明確にしておく

―「なぜ英語を勉強する?」

  • 秋にある国際学会で英語で発表する必要がある。事前に用意した発表内容のほかに、質疑応答にもしっかりと対応できるようになりたい。(直近の目標)
  • 目標としては、スピーキングでは、事前に想定したシチュエーションでは気軽にコミュニケーションができ、友達を作れるくらいになりたい。そのためには、自分が言いそうなフレーズを一通り覚えている必要がある。
  • リスニングでは、海外の俳優やエンジニアが英語でインタビューを受けている動画を聞いて理解できるようになりたい。そのためには、リアルタイムに聞いて理解できる語彙の量を増やす必要がある。

②【時間】を決めておく

【英語勉強時間】

  • 英語日記を書く・教材の予習をする(30分間)
  • 英会話レッスンを受ける(30分間)
  • 授業の復習をする・読み上げ機能を使って日記のシャドーイング(30分間)

理想は6時30分ごろに起床して朝のうちに勉強したいが、今回は所要時間のみ決めておくことにする。

③勉強過程を誰かに【報告】する

日記をインスタの非公開アカウントに投稿していき、たまに誰かに見せることにします。
ある程度期間が経ったら、ブログに経過を記録します。
ブログは、英語学習の軌跡として残ればいいと思います。

DMM英会話に初挑戦

DMM英会話の無料体験で、オンライン英会話に初挑戦しました。
以下、本当にただの日記です。

先生はフィリピンの女性講師の方で予約しました。
先生は色々な特徴で検索することができて、今回は「初心者向け」「講師歴3年以上」に加えて「キッズ向け」も条件に加えて探してみました。(優しそうなので)

予約時の要望には

This is my first lesson.
I have almost never talked in English.
Please speak slowly.

と書きました。たぶん伝わりました。

さすがに何も準備しないまま臨んでも大変なことになると思ったので、自己紹介を事前に英語で用意しておきました。

  • 基本的な自己紹介(出身・大学で学んでいること)
  • 趣味(音楽鑑賞や作曲・ゲーム・海外ドラマ(表現が分からなかったのでNetflixと言った))
  • 自分が英語を学びたい理由

また、ここ一週間で英語日記を書いてるときにどう表現すれば良いか分からなかった部分を書き出しておきました。
そして、予約をしてから始まるまでの40分間くらいで、困ったときに使えそうな英語フレーズをかき集めました。

  • What does **** mean?
  • Could you say that again?
  • Could you please speak slowly?
  • Could you type it in the chat?

で、時間になりレッスン開始です。ビデオ通話で25分間のレッスンです。
はじめに、

How was your day?

と聞かれたので、とりあえずテンプレ回答の

It was good!

と答えました。しかしそれだけでは簡単すぎると思ったので、
「ここ数日間オンライン英会話を始めようと思っていて、ついに今日始める決心をしたんだよ!」
みたいなことを言おうと思いました。

しかしどう言えばいいのかわからず...🤯
書きのテストなら1分くらい考えて英語にできそうでも、会話だと間に合いませんでした。

よく覚えてないですが、"plan", "several days", "decide"あたりの単語を使って必死に文章っぽい何かを話しました。
困りながらもなんとか伝わったようで、「い、、いいね!」みたいな反応をしてくれてたと思います。(余裕が全くなかったので覚えていない)

開始早々英語力不足に直面しながらも、気持ちを切り替えて自己紹介をしました。
先生は僕の自己紹介を聞きながらいろいろと質問してくれました。
そして僕が拙い英文で返答するたびに、雰囲気を汲み取って正しい英文を教えてくれました。

文字で見たらすぐにわかるような間違いをいくつもしてしまいました。
言いたいことを表現できそうな単語を見つけるのに必死で、文法を考える余裕が全くなかったです。

自己紹介が一段落したら、英語日記を書いていた時の疑問を質問しました。
しかし、聞き方もイマイチだったのでしっくりくる答えはもらえず、これは早めに諦めました。

最後はまた雑談に戻り、ドラマの話に。
プリズンブレイクの話になり、先生は途中までしかストーリーを知らなかったようで、マイケルは実は生きてたんだよ~とか話してたら結構盛り上がりました。

で、時間が来て終了です。
25分間、長いようで一瞬です。

感想としては、

  • "ゆっくり話してもらえば理解できる"
  • "自分の言いたいことはうまく言えない"

という感じでした。特に先生からの質問ではない発言への返答に困りました。
「ってことは~」や「それなら~」のような表現が分からなかったので、発言の糸口が難しかったです。

【次回使ってみたいフレーズ】

  • Which means, ~ 「ということは~」
  • Well then ~ 「それなら~」

でも、先生が優しかったので苦痛の時間にはならなかったです。
フリートークはまだ難しそうなので、次回は教材を使ったレッスンにしてみようと思います。

以上、今後の勉強計画とオンライン英会話初挑戦の感想でした。

3か月後の目標は https://youtu.be/v1em-y-a6Ag

]]>
2019-08-17T17:02:30.741Z
<![CDATA[Nuxt+Contentfulでmarkdown-itを使ったブログで目次を作る方法]]> https://izm51.com/posts/nuxt-contentful-blog-markdown-it-toc/ 2020-01-21T00:00:00.000Z

Nuxt.jsならJavascriptだけでブログが作れて簡単なのですが、Wordpressならプラグインで導入できるようなことでも自分で実装しなければいけないことがあり少々面倒ですね...!

今回は、記事の内容から自動で目次を生成する設定を紹介します。
markdown-itの追加プラグインで実装しています。
設定すると、↓のような目次を自動で生成することができます。

[[toc]]

使用するプラグインのインストール

今回追加するプラグインをインストールします。
markdown-it-anchor - npm : ヘッダー(h2など)までスクロールするアンカーリンクを作成する
markdown-it-table-of-contents - npm : 記事のヘッダー要素から目次を作成する

$ npm install markdown-it-anchor markdown-it-table-of-contents

インストールしたプラグインをplugins/markdownit.jsの中で読み込みます。
以前の記事で作成したplugins/markdownit.js内に以下の2行を追加します。
もしplugins/markdownit.jsがない場合は作成し、nuxt.comfig.jsのpluginsに~/plugins/markdownit.jsを追加します。

// plugins/markdownit.js
import MarkdownIt from 'markdown-it'

export default ({ app }, inject) => {

    const md = new MarkdownIt({
        html: true,
        linkify: true,
        typography: true,
    })

    md.use(require("markdown-it-anchor"))             // 追加
    md.use(require("markdown-it-table-of-contents"))  // 追加
    
   // 後略
}

ここまでで目次の自動生成ができるようになっています。
Contentfulの記事内で目次を表示したい箇所に[[toc]]と記述することで、次のような目次が生成されます。

contentful-markdown-toc

toc-preview

しかし、これだけでは目次なのか何かのリストなのか分かりにくいので、デザインを変更していきます。

目次のデザインを変更

markdown-it-table-of-contentsのプラグインで生成された目次は<div class="table-of-contents"></div>で囲まれます。
なので、このクラスのスタイルを変更していきます。
今回は以下のように設定してみます。

_slug.vue

/* scss */
    .post-content {
      padding: 0 0 15px;
      position: relative;
      z-index: 1;
      > * {
        position: relative;
        z-index: 10; // h2のpadding部分より前面に来るように
      }
      .table-of-contents {
        background: #f3f3f3;
        border: 1px solid #ccc;
        padding: 5px 10px;
        width: fit-content;
        ul {
          padding-left: 24px;
        }
        &:before {
          content: '目次';
          font-weight: bold;
          font-size: 16px;
        }
      }
    }

すると、↓のように表示できます。
CSSのbeforeセレクタで"目次"の文字を追加しています。

toc-design

目次のリンクをクリックすることで、該当するヘッダー要素までスクロールします。

しかしこのままでは、当ブログのようにブログ上部にメニューなどの固定された要素がある場合、ヘッダー要素が下に潜り込んで隠れてしまいます。 (※2020/1/21追記:現在ヘッダーの固定はスマホ表示のみにしています。)
そこで、marginとpaddingをセットすることで重ならない位置までスクロールさせることが出来ます。

当ブログではh2要素に次のようなスタイルを設定しています。

/* scss */
      h2 {
        font-size: 24px;
        margin-top: -64px;
        padding: 80px 5px 0;
        position: relative;
        z-index: 1;
        &:before {
          content: '';
          height: 34px;
          width: 100%;
          background: #d6d6d6;
          position: absolute;
          top: 80px;
          left: 0;
          z-index: -1;
        }
      }

toc-header-margin

参考にしていただければと思います!

これで、記事内のヘッダーへジャンプできる目次を自動で生成することが出来るようになりました。
あとは、目次を表示したい記事の箇所に[[toc]]を記述するのみです。

nuxtでブログを作成した際に公開したリポジトリに、これまでのmarkdown系の設定を反映したmarkdownブランチを作成しました。
Github - izm51/nuxt-blog-test at markdown

これでブログ作成時のメモが尽きたので、これからは新しいことを記事にしていきます!!
ではまた!

]]>
2019-06-25T21:36:35.316Z
<![CDATA[Nuxtで作ったブログにコメント欄を設置【Disqus】]]> https://izm51.com/posts/nuxt-blog-install-disqus/ 2019-06-16T06:53:36.896Z

個人ブログなのでコメントがつくことはあまりないかもしれませんが、Disqusのコメント欄を設置しました。
この記事では、"vue-disqus"を使ってDisqusを設置する手順を紹介します。

Disqusの作成

まず、Disqus でアカウントを作り、Create a new siteのページ を開きます。
入力事項を入力し、「Create Site」をクリック。

Disqus-create

料金プランを選ぶ画面になるので、どれかを選択。(僕の場合はBasic)

Disqus-select-plan

すると様々なプラットフォームの一覧が表示されますが、一番下の「マニュアルインストール」ボタンをクリック。

Disqus-manually

ここに表示される埋め込みタグは今回は使用しないので読み飛ばして、一番右下の「Configure」をクリック

Disqus-code

設定項目の入力欄が表示されるので、入力して「Complete Setup」をクリック

Disqus-configure

これでDisqusの設定は完了です。
しかし、コピーしておきたいものがあるので、「Configure your site's・・・」または上部メニューの「Setting」をクリックして設定画面を開きます

Disqus-complete

下の画像で赤く囲った場所に「Shortname」というキーがあるので、コピーしておきます。

Disqus--shortname

vue-disqusの設定

ここからは"vue-disqus"の設定になります。
ktquez/vue-disqusの設置方法通りとなります。

まず"vue-disqus"をインストール

$ npm install vue-disqus

plugins/disqus.jsを作成。

import Vue from 'vue'
import VueDisqus from 'vue-disqus'

Vue.use(VueDisqus)

nuxt.config.jsのプラグインに追加

  plugins: [
    '~/plugins/contentful',
    '~/plugins/markdownit',
    '~/plugins/prism',
    '~/plugins/disqus' // 追加
  ],

コメント欄を設置したい箇所に↓を追加
pages/posts/_slug.vue

  <!-- post.fields.titleにContentfulから取得した記事のタイトルが入っている -->
  <div class="comments">
    <vue-disqus shortname="your_shortname_disqus" :identifier="'post/'+post.fields.title" :url="'http://example.com/path/'+post.fields.title"></vue-disqus>
  </div> <!-- shortname等は書き換えてください -->

ログインが必要なコメント欄なので若干ハードルは高いですが、ないよりはマシだと考えてます!
はたしてコメント欄が使われるときは来るのでしょうか

ではまた。

]]>
2019-06-16T06:53:36.896Z
<![CDATA[markdown-itで外部へのリンクのみtarget="_blank"する方法]]> https://izm51.com/posts/markdown-it-target-blank-anchor/ 2019-06-15T23:59:45.465Z

4月頃、本屋で「アウトプット」系の本が多く並ぶのを見て意気込んでブログを作りましたが、
大学院生生活が思っていたより忙しく、久々の更新になってしまいました。

ブログ作成時に書き溜めていたメモがもったいないので、思い出しながら記事にしていきます。

今回は、"markdown-it"でmarkdown→HTMLの変換をする際に、

  • リンク先が相対パス(同ドメイン内)の場合は同じタブ
  • リンク先が"http"から始まる場合は新しいタブ

で開くように<a>タグにtarget="_blank"を書き加える設定を紹介します。

plugins/markdownit.jsの設定

さっそくですがソースコードです。

plugins/markdownit.js

import MarkdownIt from 'markdown-it'

export default ({ app }, inject) => {

  const md = new MarkdownIt({ //markdownitのオプション
    html: true,
    linkify: true,
    typography: true,
  })

  const defaultRender = md.renderer.rules.link_open || function (tokens, idx, options, env, self) {
    return self.renderToken(tokens, idx, options)
  }
  
  md.renderer.rules.link_open = function (tokens, idx, options, env, self) {
    const aIndex = tokens[idx].attrIndex('target')
    if (tokens[idx]['attrs'][0][1].match('http')) {
      if (aIndex < 0 ) {
        tokens[idx].attrPush(['target', '_blank'])
      } else {
        tokens[idx].attrs[aIndex][1] = '_blank'
      }
    }
    return defaultRender(tokens, idx, options, env, self);
  }

  inject('md', md)
}

nuxt.config.jsのpluginsに、markdownit.jsを追加します。
nuxt.config.jsでmarkdownitのオプションを設定していた場合は、重複してしまうので削除します。

  plugins: [
    '~/plugins/contentful',
    '~/plugins/markdownit', // 追加
    '~/plugins/prism',
  ],
  modules: [
    '@nuxtjs/dotenv',
    '@nuxtjs/markdownit'
  ],
//  オプションはplugins/markdownit.js内に移動
//  markdownit: {
//    injected: true,
//    html: true,
//    linkify: true,
//    typography: true,
//  },

下記参考リンクをもとに、リンク先の判別を追加してNuxtのプラグインとして組み込みました。
参考:Markdown-Itで独自レンダリングする方法 – 踊る犬.netブログ (旧)
参考:nuxt-community/modules

僕はブログなどの記事で別サイトへのリンクが同じタブのまま移動してしまうのがあまり好みではないので、
細かな設定ではありますがカスタマイズしてみました。

ではまた。

]]>
2019-06-15T23:59:45.465Z
<![CDATA[お名前.comのドメインが「このサイトにアクセスできません」になったときの対処法]]> https://izm51.com/posts/onamae-domain-mitukarimasen/ 2019-04-26T16:11:47.662Z

ブログをはじめようと思い立ち、ドメインを取得してから約2週間がたちました。
ところが今日、突然このブログにアクセスできなくなってしまいました。

onamae-domain-access-dekimasen

何も設定をいじっていないはずなのにと思いながら、
お名前.comとNetlifyのDNS設定を全部消しては埋めなおす作業を2回繰り返しても、何も変化なし。

しかし、原因は他の箇所でした!

onamae-domain-seigen-tuuti

メールアドレスの有効性を確認していなかったのが原因で、ドメインが一時的に停止されてました。
メール内に記載されたURLリンクからメールアドレスを有効化すると、5分ほどでウェブサイトにアクセスできるようになりました。

お名前.comに新規登録してから2週間くらいメールを有効化していないと、ドメインが制限されるようです。
登録してからドメインの割引案内メールばかりたくさん来ていたのでチェックするのをやめてしまってました。

もし登録してから2週間ほどで同様の症状に困っている方は、メールを確認してみましょう。

]]>
2019-04-26T16:11:47.662Z
<![CDATA[markdown-it + Prism.jsでシンタックスハイライト]]> https://izm51.com/posts/markdown-it-prismjs/ 2019-04-26T05:42:06.491Z

prism-0

Nuxt + Contentful + Netlifyでブログ作成の関連記事です。

当ブログでは、記事はContentful上にてMarkdown記法で作成、保存しています。
そして、Markdown記法からHTMLへの変換には"markdown-it"を使用しています。

しかし、"markdown-it"だけではソースコード部分が見づらかったため、"Prism.js"でシンタックスハイライトする設定をしました。
Nuxt.js + markdown-itでPrism.jsを使用している記事があまりなかったので、簡単にまとめてみました。

Prism.jsの導入方法

@nuxtjs/markdownitはインストール済みとして、Prism.jsをインストール

$ npm install prismjs

pluginsフォルダにprism.jsを作成します。

import Prism from 'prismjs'
import 'prismjs/themes/prism-okaidia.css'

export default Prism

2行目でimportしているcssファイルを変更すればスタイルを変更できます。
テーマは/node_modules/prismjs/themes/に入っています。
スタイルの比較はPrism.jsを参照してください。

nuxt.config.jsのプラグインに~/plugins/prism.jsを追加

  plugins: [
    '~/plugins/contentful',
    '~/plugins/prism',
  ],

Prism.jsを有効にするページのmounttdにPrism.highlightAll()を追加。

/pages/posts/_slug.vue

  mounted() {
    Prism.highlightAll()
  }

ここまでの設定で、ソースコードのシンタックスハイライトを有効にできました。
Contentful上で、以下のようにバッククォート(`)3つで囲むことでコードブロックにできます。
バッククォートの後に言語を指定することができます。

```js
export default {
  mounted() {
    console.log("mounted!")
  }
}
```

上のコードが↓のように表示されます。

prismjs-1

Line Numbersで行番号を表示

より見やすさを向上するため、行番号を表示するプラグインを有効にします。 プラグインは/node_modules/prismjs/plugins/に入っています。

先ほど作成した/plugins/prism.jsにline-numbersのプラグインを追加

import Prism from 'prismjs'
import 'prismjs/themes/prism-okaidia.css'
import 'prismjs/plugins/line-numbers/prism-line-numbers.min.js'
import 'prismjs/plugins/line-numbers/prism-line-numbers.css'

export default Prism

そして、<pre>またはその親の要素にclass="line-numbers"を設定すると、行番号が表示されるようになります。 Contentfulから取得した記事本文を表示する要素のクラスにline-numbersを追加します。

/pages/posts/_slug.vue

  <div class="post-content line-numbers" v-html="$md.render(post.fields.content)"></div>

すると行番号が表示されます。

prism-2

以上で設定完了になります。
markdown-itだけの状態と比べるとかなり見やすくなりました。

]]>
2019-04-26T05:42:06.491Z
<![CDATA[Nuxtで作ったブログにオススメの便利な設定たち(備忘録)]]> https://izm51.com/posts/nuxt-blog-first-settings/ 2020-04-03T00:00:00.000Z

前回までの記事で、Nuxt + Contentful + Netlifyでブログ作成ができました。
そこで、Nuxtでのブログ作成において設定しておいた方がよさそうな項目をリストアップしてみました。
手順についても簡単に紹介しています。
初心者なりの備忘録なので、必要な項目を見つけ次第、随時追加していきます。

[[toc]]

headとmetaタグの設定

head、metaタグによってブログのタイトルや説明文を設定します。
Nuxtではnuxt.config.jsで全ページ共通の設定に加え、各ページごとにタグの設定ができます。
注意点として、modeがuniversalでない(spaになっている)と、ページごとの設定が反映されません。
設定方法:API: head プロパティ - Nuxt.js
設定の例:SEO HTML Head - Nuxt.js

設定例
nuxt.config.js(全体で共通の設定)

  head: {
    // デフォルトとなるタイトル
    title: 'イズミログ',
    // タイトルの書式 (%sの中にtitleの文字列が入る)
    titleTemplate: '%s - Izm Log',
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'description', name: 'description', content: 'ブログの説明文' }
    ],
    link: [
      { rel: 'icon', type: 'image/x-icon', href: '/static/izm-icon.jpg' },
      { rel: 'shortcut icon', size: '196x196', href: '/static/izm-icon.jpg' },
      { rel: 'apple-touch-icon', href: '/static/izm-icon.png' }
    ]
  }

pages/posts/_slug.vue(各記事の設定)

  //this.postにContentfulから取得した記事内容が入っている
  head() {
    return {
      title: this.post.fields.title,
      meta: [
        { hid: 'description', name: 'description', content: this.post.fields.description }
    }
  }

記事ごとにheadの内容を上書きして設定することができます。
僕はContentfulのFieldsにDescriptionという説明文の入力欄を追加して、記事毎にこれを設定するようにしています。

nuxt-blog-seo-description-1

SNS用 OGPタグとTwitterカードの設定

FacebookやTwitterでシェアされた時に表示される文章や画像を設定します。
上の項目で記述したheadの設定に次のように追記していきます。

pages/posts/_slug.vue(各記事の設定)

  //this.postにContentfulから取得した記事内容が入っている
  head() {
    return {
      title: this.post.fields.title,
      meta: [
        { hid: 'description', name: 'description', content: this.post.fields.description },
        { hid: 'og:site_name', property: 'og:site_name', content: this.post.fields.title + ' - Izm Log' },
        { hid: 'og:type', property: 'og:type', content: 'website' },
        { hid: 'og:url', property: 'og:url', content: 'https://izm51.com/posts/' + this.post.fields.slug },
        { hid: 'og:title', property: 'og:title', content: this.post.fields.title },
        { hid: 'og:description', property: 'og:description', content: this.post.fields.description },
        { hid: 'og:image', property: 'og:image', content: "https:"+this.post.fields.image.fields.file.url },
        { hid: 'twitter:card', name: 'twitter:card', content: "summary" },
        { hid: 'twitter:site', name: 'twitter:site', content: "@immzm51"}
      ]
    }
  },

OGPやTwitter Cardの詳細についてはこちらのサイトが参考になります。
リンク:【WordPress】OGPとTwitterカードをプラグイン無しで設定する方法

サイトマップの生成

サイトマップを設置すると検索エンジンにサイトの構成を伝えることができ、検索にのりやすくなります。
@nuxtjs/sitemapを使用すれば、ビルド時に自動でサイトマップを生成できます。

$ npm install @nuxtjs/sitemap

nuxt.config.jsのモジュールに@nuxtjs/sitemapを追加します。
また、sitemapのセクションも追加し、sitemap生成の設定を記述します。

静的ページは自動でサイトマップに追加されます。
しかし、動的生成されるページのパスはroutesに自分で設定する必要があります。

このブログの場合は個別記事ページが動的ページです。
generateroutesの内容を少しアレンジして記述しました。
その他の設定項目は"@nuxtjs/sitemap"のReadmeを参照してください。

  modules: [
    '@nuxtjs/sitemap',
  ],
  sitemap: {
    hostname: 'https://example.com',
    routes() {
      return client
      .getEntries({ content_type: 'post' })
      .then(entries => {
        return entries.items.map(entry => {
          return "/posts/" + entry.fields.slug
        })
      })
    }
  },

Googleアナリティクスの設置

ブログの閲覧数などを解析するために、Googleアナリティクスを設置します。
@nuxtjs/google-analyticsを使用すれば設定は簡単です。

$ npm install @nuxtjs/google-analytics

'nuxt.config.js'のモジュールに'@nuxtjs/google-analytics'とアナリティクスのトラッキングIDを追加

  modules: [
    ['@nuxtjs/google-analytics', {
      id: 'UA-XXXXXXXXX-X'
    }]
  ]

詳細:Google アナリティクスの統合 - Nuxt.js

Google Search Consoleの設定

Googleの検索結果を分析するため、Google Search Consoleの設定をしておきます。
TXTレコードの設定方法など、少しややこしい箇所もあります。

まず、Google Search Consoleの入力欄にドメインを入力します。

google-search-console-0

「続行」ボタンを押すと、ドメインの所有者確認画面が表示されます。
ここで「コピー」ボタンを押し、TXTレコードをコピーします。

当ブログのようにNetlifyのネームサーバーを使用している場合は、NetlifyのDNSパネルを開きます。
Netlifyの管理ページで「Domain settings」をクリック

Netlify-domain-setting

⇓「・・・」を押し、「Go to DNS panel」をクリック

go-to-DNS-panel

⇓「Add new record」をクリック

dns-settings

⇓「Record type」を「TXT」、「Name」を「@」にし、「Value」にGoogle Search Consoleでコピーした「TXTレコード」を張り付ける。
そして「Save」をクリック

DNSの設定が反映されるまで数分待ち、Google Search Consoleの確認ボタンを押すと、設定完了の画面が表示されます。

google-search-console-2

コードのシンタックスハイライト

prism-0

プログラミング系のブログの場合、記事内にコードが多く含まれると思います。
そのプログラミングコードを見やすくするために、シンタックスハイライトを設定します。

下記記事に手順をまとめました。
markdown-it + Prism.jsでシンタックスハイライト - Izm Log

ブログの画像サーバとしてGoogleフォトを使う

(2020/4/3 追記)
下記の手順を楽にするツールを作成しました!
Googleフォトのアルバムから埋め込みコードを生成するツールを作った【ブログに便利】 - Izm Log

ContentfulではFreeタイプの場合、保存できる記事や画像などの合計個数が5000個までです。
(記事投稿時点)
5000記事にはしばらく到達しないと思いますが、
画像も合わせて5000個までとなるとすぐにオーバーしてしまいそうです。

そこで、記事はContentful、画像はGooglePhotoに保管することにしてみました。
(注:GooglePhotoの仕様変更などにより画像が表示できなくなる可能性アリ)

まず、記事に使用したい画像をGooglePhotoで開き、右上にある「共有ボタン」をクリック

GooglePhoto-Share

「リンクを作成」をクリックし、作成されたURLをコピー

GooglePhoto-Link

コピーしたURLを下記リンクの「Paste Google Photos link here..」と書いてある入力欄に張り付け、「GENERATE CODE」をクリック
https://ctrlq.org/google/photos/

generate-code-from-GooglePhoto

少し待つと画像のURLリンクが生成されます。
「Direct Link (URL)」をコピー

Copy-url

Contentfulの記事作成画面を開き、画像のURLをMarkdown記法で貼り付けます。
画像URL末尾の=w2400は、画像表示時の最大幅になるので、必要に応じて調整や消去します。

![Copy-url](https://lh3.googleusercontent.com/ayA-OhW6nWL10VxmmFb9QFsOuVUOMzHNez6s-ZNPuuJx-Q020m7v2id1rj4xUATpx7zgjsa5IDX-eEuvkikGQPnWRVbA6gB-1vPa8cAnk7hZ7L4IiRPphvzz9c3xcYCyWI8ntL0seA=w2400)
<!-- ![画像のalt属性](画像のURL) -->

以上、少し手間がかかってしまいますがGooglePhotoの画像を記事に使用する手順です。
リンクの生成に外部サービスを使用してしまっているので、より簡単な方法が見つかればアップデートします。
当ブログの画像が表示されなくなっていたら、この方法は使えなくなっている可能性が高いです。

コメント欄を設置【Disqus】

Disqus-image

"Disqus"というコメント欄を簡単に設置できるサービスを見つけたので、設置しました。

設置手順は下記記事にまとめました。
Nuxtで作ったブログにコメント欄を設置する方法【Disqus】

まとめ

このブログの作成時に設定したり、カスタマイズした項目集の備忘録でした。
必要そうな項目を見つけ次第、随時記事にしていきます!

ではまた。

]]>
2019-04-21T00:44:07.400Z
<![CDATA[Nuxt + Contentful + Netlifyでブログ作成全手順<後編>]]> https://izm51.com/posts/nuxt-contentful-netlify-blog-making-2/ 2019-04-11T22:02:50.704Z ではNuxtプロジェクトの作成からContentfulのセットアップまでの手順がまとめてあります。<後編>では記事の作成、Nuxtでの表示、Netlifyへのデプロイまでの手順をまとめていきます!]]>

Nuxt.jsを使用してブログ作成の後編です!

<前編>ではNuxtプロジェクトの作成からContentfulのセットアップまでの手順がまとめてあります。
<後編>では記事の作成、Nuxtでの表示、Netlifyへのデプロイまでの手順をまとめていきます!

[[toc]]

記事の作成

上部のメニューから「Content」をクリックし、

contentful-content-button

「Add Post」をクリック

contentful-add-post-button

記事の作成フォームが表示されるので、記事の内容を記入して「Publish」

contentful-first-post

すると、記事が作成できます。
同じ要領で2つ目の記事も作成しました。

contentful-posts

Nuxtでの記事の表示

まず、トップページに記事の一覧を表示してみます。
pages/index.vueを下記のように書き換えます。

<template>
  <div class="posts">
    <div v-for="(post, index) in posts" :key="index" class="post">
      {{ post.fields.title }}
    </div>
  </div>
</template>

<script>
import client from '~/plugins/contentful'
export default {
  asyncData({ params }) {
    return client
      .getEntries({
        content_type: 'post',
        order: '-sys.createdAt',
      })
      .then(entries => {
        return { posts: entries.items }
      })
      .catch(e => console.log(e))
  },
}
</script>

そして、下記のコマンドを実行します。

$ npm run dev

すると表示される「http://localhost:3000」のようなURLをブラウザで開くと

nuxt-contentful-posts

先ほど作成した記事のタイトル一覧が表示できました。
pages/index.vueを下記のように書き換え、少し見た目を整理してみます。

<template>
  <section class="latest-posts">
    <div class="posts">
      <nuxt-link :to="'posts/'+post.fields.slug" class="post" v-for="(post, index) in posts" :key="index">
        <div class="thumb">
          <img :src="post.fields.image.fields.file.url">
        </div>
        <div class="post-text">
          <p>{{ formatDate(post.sys.createdAt) }}</p>
          <h2>{{ post.fields.title }}</h2>
        </div>
      </nuxt-link>
    </div>
  </section>
</template>

<script>
import client from '~/plugins/contentful'
export default {
  asyncData({ params }) {
    return client
      .getEntries({
        content_type: 'post',
        order: '-sys.createdAt',
      })
      .then(entries => {
        return { posts: entries.items }
      })
      .catch(e => console.log(e))
  },
  head: {
    title: '記事一覧',
  },
  methods: {
    formatDate(iso) {
      const date = new Date(iso)
      const yyyy = new String(date.getFullYear())
      const mm = new String(date.getMonth() + 1).padStart(2, "0")
      const dd = new String(date.getDate()).padStart(2, "0")
      return `${yyyy}.${mm}.${dd}`
    }
  }
}
</script>

<style lang="scss">
section.latest-posts {
  padding: 10px;
  .posts {
    max-width: 900px;
    margin: 0 auto;
    padding: 10px;
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    background: #ddd;
    a.post {
      width: calc(100% / 2 - 20px);
      @media (min-width: (768px)) {
        width: calc(100% / 3 - 20px);
      }
      margin: 10px;
      background: #fff;
      text-decoration: none;
      color: #111;
      .thumb {
        width: 100%;
        padding-bottom: 75%;
        position: relative;
        overflow: hidden;
        img {
          position: absolute;
          top: 50%;
          left: 50%;
          transform: translate(-50%, -50%);
          max-width: 100%;
        }
      }
      .post-text {
        padding: 5px 10px 10px;
        h2 {
          width: fit-content;
          font-size: 20px;
        }
      }
    }
  }
}
</style>

すると下図のように表示できます。

nuxt-contentful-posts-arranged

これで記事の一覧ページは一旦完成とし、記事の個別ページを作成します。

pagesフォルダ内にpostsフォルダを作成します。
そして、postsフォルダ内に_slug.vueファイルを作成します。

<template>
  <article class="article">
    <div class="single">
      <h1 class="post-title">{{ post.fields.title }}</h1>
      <p class="post-created-at">{{ formatDate(post.sys.createdAt) }}</p>
      <div class="post-content" v-html="$md.render(post.fields.content)"></div>
    </div>
  </article>
</template>

<script>
import client from '~/plugins/contentful'

export default {
  asyncData({ params, error, payload }) {
    if (payload) return { post: payload }
    return client
      .getEntries({
        content_type: 'post',
        'fields.slug': params.slug,
      })
      .then(entries => {
        return { post: entries.items[0] }
      })
      .catch(e => console.log(e))
  },
  head() {
    return {
      title: this.post.fields.title,
    }
  },
  mounted() {
    console.log(this.post)
  },
  methods: {
    formatDate(iso) {
      const date = new Date(iso)
      const yyyy = new String(date.getFullYear())
      const mm = new String(date.getMonth() + 1).padStart(2, "0")
      const dd = new String(date.getDate()).padStart(2, "0")
      return `${yyyy}.${mm}.${dd}`
    }
  }
}
</script>

<style lang="scss">
article.article {
  padding: 10px;
  .single {
    max-width: 900px;
    margin: 0 auto;
    padding: 10px;
    color: #222;
    border: 2px solid #444;
    border-radius: 10px;
    h1, h2, h3 {
      margin: 16px 0;
    }
    h1.post-title {
      font-size: 32px;
      text-decoration: underline;
    }
    .post-content {
      h1 {
        font-size: 32px;
      }
      h2 {
        font-size: 24px;
        background: #ccc
      }
      p {
        margin: 16px 0;
        font-size: 16px;
      }
      img {
        max-width: 100%;
        border: 1px solid #000;
      }
    }
  }
}
</style>

そして、記事の一覧ページから個別記事のページへ移動すると

nuxt-contentful-post-single

このように、記事の内容を取得して表示ができているはずです。

markdownitを使用して、記事のマークダウン記法をHTMLタグに変換して表示しています。
細かいスタイルについてはnuxt.config.js内のmarkdownitの設定項目や、CSSによるスタイリングが必要となります。

Netlifyへのデプロイ

Netlifyへデプロイ、の前に、今まで作成したnuxtプロジェクトをGitにpushします。
新しくリポジトリを作成し、

$ git init
$ git add .
$ git commit -m "first commit"
$ git remote add origin <gitのURL>
$ git push -u origin master

次に、Netlifyのサイトで「Get started for free」ボタンから会員登録、ログインします。
(画面は2019/4/4のものになります)

netlify-get-started

右の方にある「New site from Git」ボタンをクリック

netlify-new-site-from-git

Gitのproviderを選択

netlify-github

インストールするリポジトリを選択

install-netlify

使用するリポジトリを選択し、

netlify-pick-repositry

「Build command」にnpm run generate
「Publish directory」にdistと入力し、「Show advanced」をクリック

netlify-build-options

「New variable」をクリックしてキーの入力欄を表示し、
.envファイルに記述した「CTF_SPACE_ID」と「CTF_ACCESS_TOKEN」を記入→「Deploy site」

netlify-deploy-site

「Deploying your site」と表示され、少し待つとデプロイが完了します。
「Site settings」をクリック

netlify-site-settings

左のメニューから「Build & deploy」をクリック 下へスクロールし、「Build hooks」の「Add build hook」をクリック

netlify-add-build-hook

「Build hook name」に「Deploy」と記入し、「Save」をクリック
表示された「https://api.netlify.com/build_hooks/~」 で始まるURLをコピー

netlify-build-hook

Contentfulのサイトに戻り、上部の「Settings」メニューから「Webhooks」を選択

contentful-webhook

「Add Webhook」ボタンから、Webhookの設定をします。
「Details」の「Name」に「Deploy」と記入し、「URL」の入力欄に先ほどNetlifyでコピーしたWebhookのURLを貼り付けます。
「Triggers」で「Select specific triggering events」を選択し、「Entry」にチェックを入れます。
設定が完了したら、「Save」をクリック

contentful-webhook-setting

これで、Contentful上で新しい記事の投稿や記事の編集を行うと、Webhookにより自動でNetlify上のデプロイが行われるようになります。

まとめとGithubのリンク

これにて設定が完了となり、記事の投稿とウェブサイトへの反映ができるようになりました。
ここから、ドメインの設定やデザインの変更をすることで、実際にブログとして使用できるようになると思います。

ここまでのコードをGithubで公開 しておきます。
ご自由に使用・参考にしてください!

今後は、基本的なSEOの設定や、記事のタグづけ方法なども記事にしていきたいと思っています。

]]>
2019-04-11T22:02:50.704Z
<![CDATA[Nuxt + Contentful + Netlifyでブログ作成全手順<前編>]]> https://izm51.com/posts/nuxt-contentful-netlify-blog-making-1/ 2019-04-11T22:01:42.650Z ではNuxtプロジェクトの作成からContentfulのセットアップまで、<後編>では記事の作成、Nuxtでの表示、Netlifyへのデプロイまでの手順をまとめてあります。]]>

趣味をアウトプットするためにブログをはじめようと思い立ちまして、
せっかくなので最近勉強中のNuxt.jsを使用してブログを作成してみました!
記事表示までの手順をまとめてみたので、参考にしていただければと思います!

<前編>ではNuxtプロジェクトの作成からContentfulのセットアップまで、
<後編>では記事の作成、Nuxtでの表示、Netlifyへのデプロイまでの手順をまとめてあります。

なお、この記事はこちらの動画を大いに参考にしています。
併せて参考にしていただければと思います。

[[toc]]

Nuxtプロジェクトの作成

前提条件として、nuxtはインストール済みとします。

$ npx create-nuxt-app <project-name>

nuxtで新しくプロジェクトを作成します。
設定はすべて初期設定のままです。

nuxt-create-blog1

次に必要な物をインストールします。

$ cd <project-name>
$ npm install
$ npm install contentful @nuxtjs/dotenv @nuxtjs/markdownit node-sass sass-loader

nuxt.config.jsに以下のように追加します。

require("dotenv").config() //一番上に
const client = require("./plugins/contentful")
/* ~~~中略~~~ */
  plugins: [
    '~/plugins/contentful'
  ],
  modules: [
    '@nuxtjs/dotenv',
    '@nuxtjs/markdownit'
  ],
  markdownit: {
    injected: true,
    html: true,
    linkify: true,
    typography: true,
  },
  generate: {
    routes() {
      return client
        .getEntries({ content_type: 'post' })
        .then(entries => {
          return entries.items.map(entry => {
            return {
              route: "/posts/"+entry.fields.slug,
              payload: entry
            }
          })
        })
    }
  },
  env: {
    CTF_SPACE_ID: process.env.CTF_SPACE_ID,
    CTF_ACCESS_TOKEN: process.env.CTF_ACCESS_TOKEN,
  },

pluginsフォルダにcontentful.jsを作成します。

const contentful = require("contentful")
module.exports = contentful.createClient({
  space: process.env.CTF_SPACE_ID,
  accessToken: process.env.CTF_ACCESS_TOKEN
})

nuxt.config.jsと同じ階層に.envファイルを作成します。

CTF_SPACE_ID=
CTF_ACCESS_TOKEN=

では、CTF_SPACE_IDとCTF_ACCESS_TOKENを埋めるために、contentfulのセットアップを行っていきます。

Contentfulのセットアップ

Contentfulのサイトで右上にある「Try for free」ボタンから会員登録、ログインします。
(画面は2019/4/4のものになります)

contentful-try-for-free

登録完了後、表示されるボタンを押すと「The Example Project」が作成されます。
「The Example Project」が表示されたら、左上のボタンからメニューを開き、

contentful-menu

「Create space」をクリック

contentful-create

"Space type"を選択し(僕の場合はFree)、"Space details"を記入し、進んでいけばspaceの作成は完了です。
※"Space type"が"Free"の場合、保存できる記事とアセット(画像など)の合計個数が5000個まで(記事投稿時点)のため、画像を多く使用すると比較的すぐに上限に達してしまうかもしれません。

contentful-space

「Create a content type」をクリック

contentful-create-content

記事を格納するために「Post」という名前の"Content model"を作成します。

ctf-create-new-content-type

右側の「Add field」ボタンから新しい入力欄を作成できます。
今回は下記のような"field"を作成します。

ctf-fields

まず「Title」を作成します。
「Add field」→「Text」→NameにTitleと入力→「Create and configure」

ctf-new-field

タイトルは必須項目にした方がいいと思うので、「validations」タブから「Required field」にチェックして「Save」

ctf-field-validations

これで「Title」のfieldが作成できました。

ctf-post

同様に「Slug」、「Image」、「Content」を作成します。

「Slug」は記事のURLとなる、IDのようなものです。
「Add field」→「Text」→NameにSlugと入力→「Create and configure」
→「validation」→「Required field」と「Unique field」にチェック→「Save」

「Image」は記事の一覧に表示するサムネイル画像です。
「Add field」→「Media」→NameにImageと入力→「Create and configure」
→「validation」→「Required field」にチェック→「Save」

「Content」は記事の本文です。
「Add field」→「Text」→NameにContentと入力→「Long text, full-text search」にチェック
→「Create and configure」→「validation」→「Required field」にチェック→「Save」

これらの作成が完了したら、右上にある「Save」ボタンをクリック

ctf-content-type-save

そして上部の「Settings」メニューから「API keys」を選択

ctf-get-apikey

右側の「Add API key」ボタンから、APIキーを確認することが出来ます。

ctf-apikey

ここで確認できたキーを.envファイルに記入します。

CTF_SPACE_ID=<Space ID>
CTF_ACCESS_TOKEN=<Content Delivery API - access token>

長くなってしまったため、<後編>へ続く

]]>
2019-04-11T22:01:42.650Z