# frozen_string_literal: true module PagesCore module ImagesHelper include DynamicImage::Helper def dynamic_image_tag(record_or_array, options = {}) super(record_or_array, extract_alt_text(record_or_array).merge(options)) end def image_caption(image, caption: nil) return if caption == false caption = image.caption unless caption.is_a?(String) return if caption.blank? tag.figcaption(caption) end # Renders an image figure tag with caption. # # ==== Options # * :caption: Override caption with a string, or set to false to # disable captions. # * :class_name: Class name to add to figure tag. # * :link: Link target for image. # * :ratio: Ratio to constrain image by. # * :size: Max size for image. def image_figure(image, opts = {}) class_name = ["image", image_class_name(image, ratio: opts[:ratio]), opts[:class_name]].compact image_tag = image_figure_image_tag(image, size: opts[:size], ratio: opts[:ratio]) content = opts[:link] ? image_link_to(image_tag, opts[:link]) : image_tag tag.figure(content + image_caption(image, caption: opts[:caption]), class: class_name) end # Renders an image figure tag with caption. # # ==== Options # * :caption: Override caption with a string, or set to false to # disable captions. # * :class_name: Class name to add to figure tag. # * :link: Link target for image. # * :ratio: Ratio to constrain image by. # * :sizes: Sizes attribute for image tag, default: "100vw". def picture(image, opts = {}) class_name = ["image", image_class_name(image, ratio: opts[:ratio]), opts[:class_name]].compact pict = picture_tag(image, ratio: opts[:ratio], sizes: opts[:sizes]) content = opts[:link] ? image_link_to(pict, opts[:link]) : pict tag.figure(content + image_caption(image, caption: opts[:caption]), class: class_name) end def picture_tag(image, ratio: nil, sizes: "100vw") tag.picture do safe_join( [webp_source(image, ratio:, sizes: sizes || "100vw"), dynamic_image_tag(image, size: image_size(1050, ratio), crop: (ratio ? true : false), sizes:, srcset: srcset(image, ratio:))] ) end end def original_dynamic_image_tag(record_or_array, options = {}) super(record_or_array, extract_alt_text(record_or_array).merge(options)) end def uncropped_dynamic_image_tag(record_or_array, options = {}) super(record_or_array, extract_alt_text(record_or_array).merge(options)) end private def default_image_size "2000x2000" end def extract_alt_text(record_or_array) record = extract_dynamic_image_record(record_or_array) return {} unless record.alternative? { alt: record.alternative } end def fit_ratio(size, ratio) v = Vector2d(size) Vector2d.new(v.y * ratio, v.y).fit(v) end def image_class_name(image, ratio: nil) size = ratio ? fit_ratio(image.size, ratio) : image.size return "square" if size.x == size.y return "landscape" if size.x > size.y "portrait" end def image_figure_image_tag(image, size: nil, ratio: nil) size ||= default_image_size size = fit_ratio(size, ratio) if ratio dynamic_image_tag(image, size:, crop: ratio && true, upscale: false) end def image_link_to(content, href) tag.a(content, href:) end def image_size(width, ratio) return "#{width}x" unless ratio "#{width}x#{(width / ratio).round}" end def image_widths(image) [233, 350, 700, 1050, 1400, 2100, 2800].select { |w| image.size.x >= w } end def srcset(image, ratio: nil, format: nil) image_widths(image).map do |width| options = { size: image_size(width, ratio), crop: (ratio ? true : false) } options[:format] = format if format "#{dynamic_image_path(image, options)} #{width}w" end.join(", ") end def webp_source(image, ratio: nil, sizes: "100vw") return unless webp_compatible?(image) tag.source(type: "image/webp", srcset: srcset(image, ratio:, format: :webp), sizes:) end def webp_compatible?(image) image.content_type != "image/gif" end end end