タグの配色をrubyで対応

# はじめに
[以前](https://qiita.com/youfuku/items/c53bb3a6c4d1c1689c8a)タグを扱うことがあり、そこでの対処法を備忘録として記載しておきます。
内容としては、本来CSSでやる部分をrubyでやってみようという興味範囲の記事となります

# 問題点
背景色のみを設定していたため、色合いによっては見えない等が発生していました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632357/96de0798-682d-1e93-564a-de7ad61f2807.png)

# 改修内容
今回からview_componentを利用するようにしました

送られてくる配色レコードは、「#ffffff」のような形だったので、下の記事を参考に分解するメソッドを構築
https://qiita.com/t_fujise/items/be13f5288d4423e56a64
```ruby
    def rgb_color
      @color.delete('#').each_char.each_slice(2).map { |a| a.join.to_i(16) }
    end
```

フォント色は背景色に応じて黒と白を適応させるため、以下のページを参考に計算式を利用させていただきました
http://www.asahi-net.or.jp/~gx4s-kmgi/page04.html
```ruby
  def font_color
    brightness = ((rgb_color[0] * 299) + (rgb_color[1] * 587) + (rgb_color[2] * 114)) / 1000
    if brightness < 128
      '#ffffff'
    else
      '#000000'
    end
  end
```

レコードに意図しない値が入った時の対策として、RGBの値が０の場合、強制的にタグ色が黒になる様にしました
```ruby
  def bg_color
    if rgb_color[0].zero? && rgb_color[1].zero? && rgb_color[2].zero?
      '#000000'
    else
      @color
    end
  end
```

最後にタグ色が白の場合、全体色が白だったので境界線が見づらくなると思い、線を引くようにクラスに追加するようにしました
```ruby
  def add_class
    return unless rgb_color[0] == 255 && rgb_color[1] == 255 && rgb_color[2] == 255

    'outline outline-offset-1 outline-1'
  end
```

# 全体的なソース
```ruby:tag_component.rb
class Admin::Common::TagComponent < ViewComponent::Base
  def initialize(text:, color:)
    @color = color
    @text = text
  end

  def font_color
    brightness = ((rgb_color[0] * 299) + (rgb_color[1] * 587) + (rgb_color[2] * 114)) / 1000
    if brightness < 128
      '#ffffff'
    else
      '#000000'
    end
  end

  def bg_color
    if rgb_color[0].zero? && rgb_color[1].zero? && rgb_color[2].zero?
      '#000000'
    else
      @color
    end
  end

  def add_class
    return unless rgb_color[0] == 255 && rgb_color[1] == 255 && rgb_color[2] == 255

    'outline outline-offset-1 outline-1'
  end

  private

    def rgb_color
      @color.delete('#').each_char.each_slice(2).map { |a| a.join.to_i(16) }
    end
end
```
```haml:tag_component.html.haml
%span.inline-block.rounded-xl.px-2.mx-2{style: "background-color: #{bg_color}; color: #{font_color}", class: add_class}
  = @text
```

呼び出し側
```haml
    タグ
    .flex.items-center
      = f.collection_check_boxes :tag_ids, MasterTag.use_in_e_learning, :id, :name do |tag|
        = tag.label do
          .flex.items-center.m-1
            = tag.check_box(class: 'checkbox rounded')
            = render Admin::Common::TagComponent.new(text: tag.text, color: tag.object.color_code)
```

### 完成図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632357/2295e3ca-6402-12d5-fb87-fe422d02cdad.png)

# まとめ（前回との比較）

変更前(呼び出し元)
```haml
    タグ
    = content_tag(:dev, class: 'flex items-center') do
      = f.collection_check_boxes :tag_ids, MasterTag.all, :id, :name do |tag|
        = tag.label do
          = content_tag(:dev, class: 'flex items-center m-1') do
            = tag.check_box(class: 'checkbox rounded')
            = content_tag(:dev, tag.text, class: 'badge badge-lg', style: "background-color: #{tag.object.color_code}")
```
変更後(呼び出し元)
```haml
    タグ
    .flex.items-center
      = f.collection_check_boxes :tag_ids, MasterTag.all, :id, :name do |tag|
        = tag.label do
          .flex.items-center.m-1
            = tag.check_box(class: 'checkbox rounded')
            = render Admin::Common::TagComponent.new(text: tag.text, color: tag.object.color_code)
```

変更前(デザイン)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632357/96de0798-682d-1e93-564a-de7ad61f2807.png)
変更後(デザイン)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632357/2295e3ca-6402-12d5-fb87-fe422d02cdad.png)

# さいごに
色の反転に関してはCSSでやる方法(むしろこっちが一般的？)もありますが、今回はrubyでやってみたいなーという気持ちからやってみました。
また、view_componentを使い始めたのですが、個人的にとても使いやすいと思います。
前回daisyUIのbadgeを利用していましたが、微妙にデザインが汚かったので、今回はtailwindで作成しました。
（まとめの比較画像を拡大してみてもらったら分かるかと思います）