Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions app/helpers/image_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module ImageHelper
# 画像圧縮オプション(品質85%で視覚的な劣化なく30-50%削減)
IMAGE_COMPRESSION_OPTIONS = { saver: { quality: 85 } }.freeze

# variantオプションに圧縮設定をマージ
#
# @param options [Hash] resize_to_fillなどのvariantオプション
# @return [Hash] 圧縮設定がマージされたオプション
#
# @example
# compressed_variant(resize_to_fill: [450, 300])
# # => { resize_to_fill: [450, 300], saver: { quality: 85 } }
def compressed_variant(options)
options.merge(IMAGE_COMPRESSION_OPTIONS)
end
end
3 changes: 2 additions & 1 deletion app/views/shared/_membership_avatar.html.erb
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<% size ||= 60 %>
<% initial_font_size ||= 'sm' %>
<% lazy ||= true %>

<% if membership.avatar.attached? %>
<div style="width: <%= size %>px; height: <%= size %>px;" class="mx-auto rounded-full bg-gray-200">
<%= image_tag membership.avatar.variant(resize_to_fill: [size, size]), alt: "#{membership.display_name}のアバター", class: "w-#{size/4} h-#{size/4} rounded-full object-cover" %>
<%= image_tag membership.avatar.variant(compressed_variant(resize_to_fill: [size, size])), alt: "#{membership.display_name}のアバター", class: "w-#{size/4} h-#{size/4} rounded-full object-cover", loading: lazy ? "lazy" : "eager" %>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Tailwind CSSのJITコンパイラは、ソースコード内に完全な文字列として存在するクラス名しか検出できません。"w-#{size/4}" のように動的にクラス名を生成すると、意図したスタイルが適用されない可能性があります。

また、親要素が width: <%= size %>px; height: <%= size %>px; となっているため、画像をコンテナいっぱいに表示するには w-full h-full を使用するのが適切だと思われます。

object-cover と組み合わせることで、アスペクト比を維持したままコンテナを埋めることができます。

<%= image_tag membership.avatar.variant(compressed_variant(resize_to_fill: [size, size])), alt: "#{membership.display_name}のアバター", class: "w-full h-full rounded-full object-cover", loading: lazy ? "lazy" : "eager" %>

</div>
<% else %>
<div style="width: <%= size %>px; height: <%= size %>px;" class="mx-auto rounded-full bg-gray-500 flex items-center justify-center text-white">
Expand Down
4 changes: 2 additions & 2 deletions app/views/teams/events/_main_column.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

<% if event.image.attached? %>
<div class="aspect-[3/2] mb-6 bg-gray-200">
<%= image_tag event.image.variant(resize_to_fill: [1500, 1000]), alt: "#{event.name}のイメージ画像", class: "w-full h-full object-cover" %>
<%= image_tag event.image.variant(compressed_variant(resize_to_fill: [1500, 1000])), alt: "#{event.name}のイメージ画像", class: "w-full h-full object-cover" %>
</div>
<% else %>
<div class="aspect-[3/2] mb-6 bg-gray-300 flex items-center justify-center text-white">
Expand Down Expand Up @@ -127,7 +127,7 @@
<div data-tabs-target="panel" data-tab="report" class="<%= event.report_available? ? '' : 'hidden' %> py-6">
<% if event.report_image.attached? %>
<div class="aspect-[3/2] mb-6 bg-gray-200">
<%= image_tag event.report_image.variant(resize_to_fill: [1500, 1000]), alt: "#{event.name}の開催レポート画像", class: "w-full h-full object-cover" %>
<%= image_tag event.report_image.variant(compressed_variant(resize_to_fill: [1500, 1000])), alt: "#{event.name}の開催レポート画像", class: "w-full h-full object-cover", loading: "lazy" %>
</div>
<% end %>

Expand Down
2 changes: 1 addition & 1 deletion app/views/teams/memberships/_event_item.html.erb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<%= link_to team_event_path(@team, event), class: "flex gap-4 py-4 border-t border-gray-200" do %>
<div class="w-[120px] md:w-[150px] h-[80px] md:h-[100px] bg-gray-200 relative flex-shrink-0">
<% if event.image.attached? %>
<%= image_tag event.image.variant(resize_to_fill: [150, 100]), alt: "#{event.name}のイメージ画像", class: "w-full h-full object-cover" %>
<%= image_tag event.image.variant(compressed_variant(resize_to_fill: [150, 100])), alt: "#{event.name}のイメージ画像", class: "w-full h-full object-cover", loading: "lazy" %>
<% else %>
<div class="aspect-[3/2] bg-gray-500 flex items-center justify-center text-white">
<span class="text-xs md:text-md">No Image</span>
Expand Down
4 changes: 2 additions & 2 deletions app/views/teams/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<div class="aspect-[3/2] bg-gray-200 relative">
<% if event.image.attached? %>
<div class="aspect-[3/2] mb-3 bg-gray-200">
<%= image_tag event.image.variant(resize_to_fill: [450, 300]), alt: "#{event.name}のイメージ画像", class: "w-full h-full object-cover" %>
<%= image_tag event.image.variant(compressed_variant(resize_to_fill: [450, 300])), alt: "#{event.name}のイメージ画像", class: "w-full h-full object-cover", loading: "lazy" %>
</div>
<% else %>
<div class="aspect-[3/2] mb-3 bg-gray-500 flex items-center justify-center text-white">
Expand Down Expand Up @@ -167,7 +167,7 @@
<div class="aspect-[3/2] bg-gray-200 relative">
<% if event.image.attached? %>
<div class="aspect-[3/2] mb-3 bg-gray-200">
<%= image_tag event.image.variant(resize_to_fill: [450, 300]), alt: "#{event.name}のイメージ画像", class: "w-full h-full object-cover" %>
<%= image_tag event.image.variant(compressed_variant(resize_to_fill: [450, 300])), alt: "#{event.name}のイメージ画像", class: "w-full h-full object-cover", loading: "lazy" %>
</div>
<% else %>
<div class="aspect-[3/2] mb-3 bg-gray-500 flex items-center justify-center text-white">
Expand Down
20 changes: 20 additions & 0 deletions spec/helpers/image_helper_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
require 'rails_helper'

RSpec.describe ImageHelper, type: :helper do
describe '#compressed_variant' do
it '圧縮オプションをマージして返す' do
result = helper.compressed_variant(resize_to_fill: [ 450, 300 ])
expect(result).to eq(resize_to_fill: [ 450, 300 ], saver: { quality: 85 })
end

it '既存のオプションを保持しつつ圧縮オプションを追加する' do
result = helper.compressed_variant(resize_to_limit: [ 1000, 1000 ], format: :webp)
expect(result).to eq(resize_to_limit: [ 1000, 1000 ], format: :webp, saver: { quality: 85 })
end

it '空のハッシュにも圧縮オプションを追加する' do
result = helper.compressed_variant({})
expect(result).to eq(saver: { quality: 85 })
end
end
end