アカベコマイリ

HEAR NOTHING SEE NOTHING SAY NOTHING

Redmine テーマ minimalflat2 v1.2.0 リリース

Redmine v3.3 が提供されたので、それに対応する minimalflat2 v1.2.0 をリリースした。

Redmine v3.3 標準テーマは v3.2 以前と互換がないため minimalflat2 v1.2.0 も Redmine v3.3 以降をサポート対象とする。旧バージョンを Releases に残しておくので古い Redmine 対応版が必要な場合はこちらを利用してもらう。v1.1.5 の Release Notes にも、これが Redmine v3.2 をサポートする最終版であることを記載しておいた。

以下は作業記録。

Redmine 3.2 と 3.3 の差分反映

minimalflat v1.0.0 では Redmine v3.1 の application.css を Stylus 化して部位ごとにファイルを分割した。このテーマでは標準の application.css を import せず、すべてのスタイルを独自定義している。そのため自身で管理しやすいように Stylus を構成。

しかし Redmine 本体側の変更を確認する際に application.css の前後バージョン diff と Stylus を一致させるのが面倒になってきた。そこで今回から、Stylus ファイルの分割は最小にとどめ、元の 定義順をなるべく維持するようにした。ファイルこそ長大になったものの差分の確認と反映がおこないやすい。ちなみに diff は以下のようにチェックしている。

  1. Download - Redmine から差分を確認する前後バージョンを入手
  2. それぞれの application.cssresponsive.css の diff を FileMerge でチェック

FileMerge というのは Xcode 付属の GUI つき diff ツールである。単体で起動するために

/Applications/Xcode.app/Contents/Applications/FileMerge.app

を Dock に登録している。Finder からアクセスする場合は Xcode.app のコンテキストメニューからパッケージの内容を表示を選択して Contents > Applications を開く。

余談だが Contents > Developer > Applications には iOS シミュレータもある。これを Dock に入れておくと便利だ。Web フロントエンド開発しているとき browser-sync とかでホストさせて iOS シミュレータ上の Safari から動作確認したりする。

.icon と .icon-only

Redmine v3.2 まではチケットのコメント編集アイコンなどは <img> になっていた。v3.3 ではこれらの設計が改善されて <a> の背景画像に変更されている。

minimalflat2 ではアイコンをフォントにしており、対象となる要素の before 擬似要素に定義している。しかし <img>置換要素だから擬似要素は利用不能。仕方ないので theme.js によって特定の src 属性を持つ <img? を検出したら <i> へ置換するようにしていた。

この処理は無駄であるうえ <img>click が指定されていたら継承が必要などの問題がある。v3.3 でようやくこの対策処理が不要になった。最新の theme.js ではプロジェクト一覧画面のツリー開閉 UI だけ担当している。

アイコンに関連しては、もうひとつ重要な変更がある。

これまで minimalflat2 では .icon を定義していなかった。これはアイコン関連をすべてフォントに置き換えるため、標準の background-imagepadding 系を組み合わせた指定が干渉するためである。

しかし今回から .icon-only と共に標準のスタイル指定そのままに移植するようにした。どうやら一部の Redmine プラグインでは標準の .icon に依存しているらしく、それらへ個別対応するのはキツイ。ならばこの定義を残して必要な部分だけ上書きするほうが設計的に好ましいと判断した。

上書きの工夫について。まずは普通に Stylus で

.icon {
  background-position 0% 50%
  background-repeat no-repeat
  padding-left 20px
  padding-top 2px
  padding-bottom 3px
}

.icon-only {
  background-position 0% 50%
  background-repeat no-repeat
  padding-left 16px
}

と定義。しかし HTML 上の .icon.icon-only の指定は

<a title="Delete relation" class="icon-only icon-link-break">Delete relation</a>

のようになっている。そのまま .icon-XXXX:before でアイコン フォントを指定すると .icon.icon-only のレイアウトに影響されてしまう。これを上書きするため、

.icon {
  &.icon-link-break,
  &.icon-link-edit, ... {
    padding 0
  }
}

.icon-only {
  &.icon-link-break,
  &.icon-link-edit, ... {
    width 1.3em
    height 1.3em
    padding 0
    font-size 1em
    color transparent !important

    &:after {
      content ""
    }
  }
}

とした。Stylus は & で親階層を表す。そのためこれらは .icon.icon-link-break という形式へコンパイルされる。つまり class として同時指定された時のみ定義を上書きして影響を相殺しているのだ。

  • *2016/7/13 修正 v1.2.0 時点では height:auto にしていた。しかしこの指定だと透明にしたテキストが width に満たず折り返されたとき、その分の高さが計上されてレイアウトが崩れる。そのため heightwidth と同じ固定値へ修正。また color は issue の関連チケット表示で優先度の高いものがあると、それに対して色が指定されるため transparent だけだと詳細度の関係でテキストが可視化されてしまう。よって !important により透明化を強制するようにした。

階層化されたプロジェクトのタイトル

従来、階層化されたプロジェクトのタイトルはこんな感じの HTML になっていた。

<h1>
  <a class="root" href="/redmine/projects/root?jump=overview">Root</a> »
  <a class="ancestor" href="/redmine/projects/parent?jump=overview">Parent</a> »
  Current
</h1>

class こそ設定されているが、テーマで明示的に指定しない限り文字サイズは <h1> なので、長いタイトルが続くとレイアウトが崩れる問題があった。Redmine v3.3 ではこれが改善されて

<h1>
  <span class="breadcrumbs">
    <a class="root" href="/projects/root?jump=overview">Root</a>
    <span class="separator"> » </span>
    <a class="ancestor" href="/projects/parent?jump=overview">Parent</a>
    <span class="separator"> » </span>
  </span>
  <span class="current-project">Current</span>
</h1>

となる。そして CSS では

#header h1 .breadcrumbs {
  display: block;
  font-size: .6em;
  font-weight: normal;
}

のように文字サイズ調整されていた。つまり上層プロジェクトのタイトルは小さくなる。あわせて他方で text-overflow:ellipsiswhite-space:nowrap が指定されているのでカレントを目立たせつつ長さを短縮、行が維持されてレイアウト崩れは回避された。

しかし minimalflat2 ではタイトルの <h1> に対して before 擬似要素でアイコン表示している。そのため .breadcrumbsdisplay:block が影響して改行されてしまう。よって display:inline-block へ修正する必要があった。

これは minimalflat2 独自の事情だが、それを抜きにしてもインライン要素についてレイアウト互換を維持しながらブロック要素にするならば、displayinline-block にしておくのが無難である。

リリース用 ZIP ファイル名処理の改善

これは前バージョンで対応した内容だが、記録していなかったので改めて。

minimalflat2 は GitHub プロジェクトの Releases に ZIP ファイルとしてリリースしている。このファイル、名前にバージョン番号を付与しているのだが、これまでは npm-scripts で変数を参照できなかったため以下のようにハードコードしていた。

{
  "scripts": {
    "release:archive": "bestzip minimalflat2-v1.1.5.zip ./minimalflat2"
  }
}

バージョン番号の設定はプロジェクトにひとつであるべきだ。minimalflat2 はプロジェクト情報を package.json で管理しているから、その version を一意として参照するのが好ましい。というわけで cross-conf-env を利用して以下のように修正。

{
  "version": "1.2.0",
  "scripts": {
    "release:archive": "cross-conf-env bestzip minimalflat2-vnpm_package_version.zip ./minimalflat2"
  }
}

ハードコードしていた部分が npm_package_version になっている。これは process.env.npm_package_version に相当し、cross-conf-env が解析して当該変数の値に置換してから bestzip に処理を受け渡す。

この対応により今後は version を修正するだけで ZIP ファイル名へ反映されるようになった。