Hugoでレスポンシブなブログカードを作成する

2020-06-20 Hugo ブログカード

目次

やりたいこと

  • Hugo でブログカードを作成したい
  • レスポンシブなデザインにしたい(スマートフォンで見たときに画像サイズ等を変更したい)

レスポンシブなブログカードの例:

やったこと

1. OGPを取得するサーバを作成する

下記のサイトを参考にしました.

まず,指定したURLからOGP情報を取得し,JSON形式でレスポンスするサーバを作成します. サーバ用のディレクトリを作成し,npmの設定を行い,app.jsを実行します.

コマンド:

$ mkdir blog_card
$ cd $_
$ npm init
$ npm install express --save
$ npm install npm install cheerio-httpcli --save
$ node app.js

app.js:

//app.js

// import * as express from 'express';
// import * as client from 'cheerio-httpcli';
// const app = express();

var express = require('express');
var client = require('cheerio-httpcli');
var app = express();

app.get("/getogp", (expressRequest, expressResponse, expressNext) => {
    const url = expressRequest.query.url;
    client.fetch(url, (err, $, res, body) => {
        if (err) {
            expressNext(err)
            return;
        }

        const result = {
            exists: false,
            title: "",
            description: "",
            url: "",
            image: "",
            site_name: "",
            type: "",
        }

        const ogTitleQuery = $("meta[property='og:title']");

        if (ogTitleQuery.length > 0) {
            result.exists = true;
            result.title = $("meta[property='og:title']").attr("content");
            result.description = $("meta[property='og:description']").attr("content");
            result.url = $("meta[property='og:url']").attr("content");
            result.image = $("meta[property='og:image']").attr("content");
            result.site_name = $("meta[property='og:site_name']").attr("content");
            result.type = $("meta[property='og:type']").attr("content");
        } else {
            result.title = $("head title").text()
            result.description = $("meta[name='description']").attr("content");
        }

        expressResponse.json(result);
    });
})

app.listen(6060, () => console.log('Listening on port 6060'));

ほとんどコピペさせていただきましたが,下記のエラーが出たため,モジュールのimport方法だけ変更して使用しています.

import * as express from 'express';
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at wrapSafe (internal/modules/cjs/loader.js:1101:16)
    at Module._compile (internal/modules/cjs/loader.js:1149:27)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1205:10)
    at Module.load (internal/modules/cjs/loader.js:1034:32)
    at Function.Module._load (internal/modules/cjs/loader.js:923:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12)
    at internal/main/run_main_module.js:17:47

以上の設定により,shortcodeからgetJSON http://localhost:6060/getogp?url=WebページのURLを実行することで,OGP情報をJSON形式で取得することができます.

2. blogcard用のshortcodeを作成する

こちらは主に下記のサイトを参考にしました.

下記のファイルをlayouts/shortcodes/blogcard.htmlに作成します.

blogcard.html:

<!-- blogcard.html -->
{{ $url := ( .Get 0) }}
{{ $function := print "http://localhost:6060/getogp?" (querify "url" $url )}}
{{ $ogpjson := getJSON $function }}

{{ $urlp := urls.Parse $url }}

  <div class="blogcard">
  <a href="{{ $ogpjson.url }}">
   <div class="blogcard_thumbnail"> 
        <img class="blogcard_img"
            src="{{ $ogpjson.image }}"
            alt="{{ $ogpjson.title }}"
            width="150"
            height="150">
    </div>
   <div class="blogcard_content">
    <div class="blogcard_title"> 
        <strong>
            {{ $ogpjson.title | truncate 50}}
        </strong>            
    </div>
    <div class="blogcard_excerpt">{{ $ogpjson.description | truncate 70}}</div>
   </div>
   <div class="blogcard_host">
       {{ $urlp.Host }}
   </div>
   <div class="clear"></div>
  </a>
  </div>

こちらもほぼコピペですが,下記の点に変更を加えています.

  • 「3.レスポンシブなブログカード用にCSSを設定」に合わせて出力HTMLの部分を書き換え
  • URLからホスト名を取得し,表示する機能を追加
  • タイトルの上限文字数を50文字に制限

3. レスポンシブなブログカード用にCSSを設定

下記のサイトを参考にしました.

下記の記述をstatic/css/custom.cssに追加します.

custom.css:

/* custom.css */
.blogcard {
  line-height: 1;
  background-color: #ffffff;
  border: 1px solid #eeeeee;
  word-wrap: break-word;
  margin: 40px;
  box-shadow: 0 0 10px 6px rgba(0,0,0,.025);
  overflow: hidden;
}
.blogcard a {
  text-decoration: none;
  opacity: 1;
  transition: all 0.2s ease;
}
.blogcard a:hover {
  opacity: 0.6;
}
.blogcard_thumbnail {
  float: left;
  padding: 0px;
  padding-right:20px;
}

.blogcard_title {
  font-size: 1em;
  font-weight: bold;
  line-height: 1.4;
  padding: 17px 20px 10px;  
  color:black;
}
.blogcard_excerpt {
  font-size: 0.9em;
  line-height: 1.6;
  padding: 0 17px 15px 20px;
  color:black;
  opacity:0.5;
}

@media screen and (max-width: 768px) {
  .blogcard {
    margin: 40px 0;
  }
  .blogcard_title {
    font-size: 0.9em;
    padding-bottom: 17px;
  }
  .blogcard_excerpt  {
    display: none;
  }
  .blogcard_img{
    width:100px;
    height:100px;
  }

こちらについても,元サイトから一部変更を行っています.

  • フォント色の変更(黒)
  • @mediaで画像のサイズを変更 等

4. 記事内でショートコードを使用する

下記のように記載することで,簡単にレスポンシブなブログカードを追加することができます.

{{% blogcard "https://dis-play.net/wordpress/tips/blogcard/" %}}

iframelyは利用を中断

下の記事で書いた通り,しばらくiframelyでブログカードを作成していました.

しかし,iframelyの無料プランには,1000 hits/月という制限があります. 今回,利用開始の初月に,早くもこの制限に引っかかってしまったため,別の方法を探すことにしました.

  • 毎月29ドル:10,000hits/月
  • 毎月49ドル:50,000hits/月
  • 毎月99ドル:150,000hits/月
  • 毎月399ドル:1,000,000hits/月

というプランもありますが,お金をかけ始めると際限なさそうなので,今回は無料でできる方法を試すことにしました.

今後の課題

  • Amazonの商品はOGP情報から画像が取得できない.Amazonの商品リンク用のshortcodeを作成する.
  • CSSを一部修正する.
comments powered by Disqus