Hori Blog

フリーランスでバックエンドエンジニアとして活動している Ryota Hori のブログです。
最近はテック系記事より雑記ブログ気味。

良い感じにスライドを作れる Talkie をラップした talkiego を作った

ここのところ、プレゼン用スライドの制作は @ahomu さん製の Talkie をお借りしているのですが、 Talkie はソースを丸っと落として index.html を編集する必要があります。

Markdown だけ記述してコマンド一発で起動できるようにしたかったので talkiego を作りました。

Talkie とは

ahomu/Talkie: Simple slide presentation library. Responsive scaling & markdown ready.

Talkie@ahomu さん製の良い感じにおしゃれなスライドを作れるライブラリです。

似たようなツールとして reveal.js があるのですが、個人的には Talkie の方が日本語のレイアウトが綺麗に決まるので Talkie を愛用しています。

reveal.js でもダメではないのですが、ちょっと真ん中にギュッと寄ってしまう感がありまして、好みではなかったです。

talkiego とは

talkiego は Markdown ファイル単体を引数で取れば Talkie で起動してくれるツールです。

reveal.js でいうところの yusukebe/revealgo です。

作った経緯

Talkie は Node.js 製で、使用するには index.html の編集が必要になります。 slide を作るときに丸っと Talkie を落として編集するのではなくコンテンツ部分だけ書かれた Markdown ファイルを読み込むようにしたかったのが動機です。

使い方

talkiego の README.md に書いてありますが、簡単に載せておきます。

Talkie の index.html だとこんな感じで書きますが、

index.html
<html>
<head>
  <meta charset="utf-8">
  <title>Talkie.js - HTML/CSS/JavaScript Presentation Library</title>
  <link rel="stylesheet" href="./dist/talkie.min.css">
  <link rel="stylesheet" href="./dist/talkie-default.min.css">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.9.1/styles/monokai_sublime.min.css">
</head>
<body>

<!-- put your slides -->

<template layout="cover" type="text/x-markdown">
# Talkie.js
</template>

<template layout="title" invert type="text/x-markdown"
          backface="https://farm8.staticflickr.com/7469/16209884502_211d01ac0d_z_d.jpg"
          backface-filter="blur(3px) brightness(.9)">
# Backface (北極)
</template>

<script layout="bullets" type="text/x-markdown" style="color:#ff0000;">
* foo
* bar
* baz
</script>

<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.9.1/highlight.min.js"></script>
<script src="./dist/talkie.min.js"></script>
<script>
  var talkie = Talkie({
      wide: true,
      control: true
  });
  document.addEventListener('DOMContentLoaded', function() {
    talkie.changed.subscribe(function(current) {
      console.clear();
      // print presenter notes
      console.info(talkie.notes[current.getAttribute('data-page')]);
    });
  });
</script>
</body>
</html>

talkiego だとこうなります。

index.md
<!-- rootopt: wide control -->

<!-- cover: -->
# Talkie.js

---

<!-- title: invert
            backface=https://farm8.staticflickr.com/7469/16209884502_211d01ac0d_z_d.jpg
            backfaceFilter="blur(3px) brightness(.9)" -->
# Backface (北極)

---

<!-- bullets: style="color:#ff0000;" -->

* foo
* bar
* baz

で、この作った Markdown ファイル (index.md) を引数にとって起動します(デフォルト値は index.md にしてあります)。

talkiego serve index.md

backface などのオプションの記述は必要ですが、コンテンツだけを独立した Markdown ファイルにできました。

Markdown ファイルだけなので、企画案などのペライチを量産するときにもとても捗ります。

実装について

とりあえずコマンドなのでベースは spf13/cobra を使用しました。

Talkie は Node.js ですが、スライドを動かすには dist ディレクトリに生成される静的ファイルを用いれば Node サーバの起動はしなくても動かせます。よって今回は jessevdk/go-assets で Talkie のデフォルトテンプレートファイルを Go のソースコードにバイナリとして埋め込み、 FileServer として使用することでファイルを返せるようにしました。

assets 系の埋め込みは jteeuwen/go-bindata も人気ですが、今回はシンプルにファイルサーバとして使用するので http.FileSystem の実装を持っている jessevdk/go-assets を使用しています。

大変だったところ

オプションのダブルクォーテーションをオプショナルにしたため、 parser を自作する羽目になりちょっと苦労しました。複数行も対応したため、空白で分割した後に quoted 状況に応じて結合したりなどなど。 CSV ファイルを扱うときもそうなのですが、良い感じでダブルクォーテーションを扱ってくれるライブラリが欲しいところです。

parser.go
func parseProps(s string) map[string]string {
	dst := map[string]string{}
	fs := strings.Fields(s)

	for i := 0; i < len(fs); i++ {
		// split key:value or key=value
		sep := strings.IndexAny(fs[i], ":=")
		if sep < 0 {
			dst[fs[i]] = ""
			continue
		}

		k, v := fs[i][:sep], fs[i][sep+1:]

		if !strings.HasPrefix(v, "\"") {
			dst[k] = v
			continue
		}

		// quoted
		i++
		for i < len(fs) {
			v = fmt.Sprintf("%s %s", v, fs[i])
			if strings.HasSuffix(fs[i], "\"") && !strings.HasSuffix(fs[i], "\\\"") {
				break
			}
			i++
		}

		dst[k] = strings.Trim(v, "\"")
	}
	return dst
}

とりあえず必要な書式で動けばいいやーと思いざっくり実装にしてあるので、正確な quoted の挙動にはなっていないかもしれませんが、及第点としたいところ。

今後の展望

このへんはあると便利だなーと思ってはいますが、とりあえず自分はデフォルトテンプレートがあれば困っていないのでどうしようかなと。

  • Talkie のディレクトリを指定すると埋め込んだ assets ではなく指定した Talkie を見る
  • Talkie のオプション( wide など。勝手に RootOpt と呼んでいる)をコマンド引数で指定できるように
  • watch オプションで変更検知
  • カスタム CSS ファイルなどを読み込めるように
  • HOME ディレクトリらへんにコンフィグファイルを置いて、デフォルト設定として用いる
  • オプションのエイリアスやシンボル、モジュール化

プルリクお待ちしております。

以上

スライドを作らなければいけないと思うと急にツールを整えたくなる病でカッとなって作ったのですが、狙い通り便利なものができたので捗っています。

デザインセンスが無いので、ネタだけ用意すれば見た目はそれっぽくしてくれるツール群は本当に助かります。ありがとうございます。