Skip to content

Commit

Permalink
Merge pull request #2465 from tvdeyen/view-components
Browse files Browse the repository at this point in the history
Use view_component for ingredient views
  • Loading branch information
tvdeyen authored May 24, 2023
2 parents c72e3cd + f36872d commit 4a04814
Show file tree
Hide file tree
Showing 51 changed files with 700 additions and 298 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ group :development, :test do
# minimal, but breaking.
gem "execjs", "= 2.8.1"
gem "jsbundling-rails", "~> 1.1"
gem "rubocop", require: false
gem "standard", "~> 1.25", require: false
gem "selenium-webdriver", "< 4.9.1" # until https://github.com/teamcapybara/capybara/pull/2665 got merged

Expand Down
1 change: 1 addition & 0 deletions alchemy_cms.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ Gem::Specification.new do |gem|
gem.add_runtime_dependency "simple_form", [">= 4.0", "< 6"]
gem.add_runtime_dependency "sprockets", [">= 3.0", "< 5"]
gem.add_runtime_dependency "turbolinks", [">= 2.5"]
gem.add_runtime_dependency "view_component", ["~> 3.0"]

gem.add_development_dependency "capybara", ["~> 3.0"]
gem.add_development_dependency "capybara-screenshot", ["~> 1.0"]
Expand Down
37 changes: 37 additions & 0 deletions app/components/alchemy/ingredients/audio_view.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
module Alchemy
module Ingredients
class AudioView < BaseView
def call
content_tag(:audio, **html_options) do
tag(:source, src: src, type: type)
end
end

def render?
!!ingredient.attachment
end

private

def src
alchemy.show_attachment_path(
ingredient.attachment,
format: ingredient.attachment.suffix
)
end

def type
ingredient.attachment.file_mime_type
end

def html_options
{
controls: ingredient.controls,
autoplay: ingredient.autoplay,
loop: ingredient.loop,
muted: ingredient.muted
}
end
end
end
end
27 changes: 27 additions & 0 deletions app/components/alchemy/ingredients/base_view.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
module Alchemy
module Ingredients
class BaseView < ViewComponent::Base
attr_reader :ingredient, :html_options

delegate :alchemy, to: :helpers
delegate :value, to: :ingredient

# @param ingredient [Alchemy::Ingredient]
# @param html_options [Hash] Options that will be passed to the wrapper tag.
def initialize(ingredient, html_options: {})
raise ArgumentError, "Ingredient missing!" if ingredient.nil?

@ingredient = ingredient
@html_options = html_options
end

def call
value
end

def render?
value.present?
end
end
end
end
13 changes: 13 additions & 0 deletions app/components/alchemy/ingredients/boolean_view.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module Alchemy
module Ingredients
class BooleanView < BaseView
def call
Alchemy.t(value, scope: "ingredient_values.boolean")
end

def render?
!value.nil?
end
end
end
end
26 changes: 26 additions & 0 deletions app/components/alchemy/ingredients/datetime_view.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module Alchemy
module Ingredients
class DatetimeView < BaseView
# @param ingredient [Alchemy::Ingredient]
# @param date_format [String] The date format to use. Use either a strftime format string, a I18n format symbol or "rfc822".
def initialize(ingredient, date_format: nil, html_options: {})
super(ingredient)
@date_format = date_format
end

def call
if date_format == "rfc822"
ingredient.value.to_s(:rfc822)
else
::I18n.l(ingredient.value, format: date_format)
end
end

private

def date_format
@date_format || ingredient.settings[:date_format]
end
end
end
end
43 changes: 43 additions & 0 deletions app/components/alchemy/ingredients/file_view.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
module Alchemy
module Ingredients
class FileView < BaseView
delegate :attachment, to: :ingredient

# @param ingredient [Alchemy::Ingredient]
# @param link_text [String] The link text. If not given, the ingredients link_text setting or the attachments name will be used.
# @param html_options [Hash] Options that will be passed to the a tag.
def initialize(ingredient, link_text: nil, html_options: {})
super(ingredient, html_options: html_options)
@link_text = link_text
end

def call
link_to(
link_text,
attachment.url(
download: true,
name: attachment.slug,
format: attachment.suffix
),
{
class: ingredient.css_class.presence,
title: ingredient.title.presence
}.merge(html_options)
)
end

def render?
!attachment.nil?
end

private

def link_text
ingredient.link_text.presence ||
ingredient.settings[:link_text].presence ||
@link_text.presence ||
attachment&.name
end
end
end
end
15 changes: 15 additions & 0 deletions app/components/alchemy/ingredients/headline_view.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module Alchemy
module Ingredients
class HeadlineView < BaseView
def call
content_tag "h#{ingredient.level}",
ingredient.value,
id: ingredient.dom_id.presence,
class: [
ingredient.size ? "h#{ingredient.size}" : nil,
html_options[:class]
]
end
end
end
end
9 changes: 9 additions & 0 deletions app/components/alchemy/ingredients/html_view.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module Alchemy
module Ingredients
class HtmlView < BaseView
def call
value.to_s.html_safe
end
end
end
end
29 changes: 29 additions & 0 deletions app/components/alchemy/ingredients/link_view.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
module Alchemy
module Ingredients
class LinkView < BaseView
attr_reader :text

# @param ingredient [Alchemy::Ingredient]
# @param text [String] The link text. If not given, the ingredient's text setting or the value will be used.
# @param html_options [Hash] Options that will be passed to the a tag.
def initialize(ingredient, text: nil, html_options: {})
super(ingredient, html_options: html_options)
@text = text
end

def call
link_to(link_text, value, {target: link_target}.merge(html_options))
end

private

def link_text
text || ingredient.settings[:text] || value
end

def link_target
(ingredient.link_target == "blank") ? "_blank" : nil
end
end
end
end
11 changes: 11 additions & 0 deletions app/components/alchemy/ingredients/node_view.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module Alchemy
module Ingredients
class NodeView < BaseView
delegate :node, to: :ingredient

def call
render(node)
end
end
end
end
15 changes: 15 additions & 0 deletions app/components/alchemy/ingredients/page_view.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module Alchemy
module Ingredients
class PageView < BaseView
delegate :page, to: :ingredient

def call
link_to page.name, alchemy.show_page_path(urlname: page.urlname)
end

def render?
!!page
end
end
end
end
108 changes: 108 additions & 0 deletions app/components/alchemy/ingredients/picture_view.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# frozen_string_literal: true

module Alchemy
module Ingredients
# Renders a picture ingredient view
class PictureView < BaseView
attr_reader :ingredient,
:show_caption,
:disable_link,
:srcset,
:sizes,
:html_options,
:picture_options,
:picture

# @param ingredient [Alchemy::Ingredient]
# @param show_caption [Boolean] (true) Whether to show a caption or not, even if present on the picture.
# @param disable_link [Boolean] (false) Whether to disable the link even if the picture has a link.
# @param srcset [Array<String>] An array of srcset sizes that will generate variants of the picture.
# @param sizes [Array<String>] An array of sizes that will be passed to the img tag.
# @param picture_options [Hash] Options that will be passed to the picture url. See {Alchemy::PictureVariant} for options.
# @param html_options [Hash] Options that will be passed to the img tag.
# @see Alchemy::PictureVariant
def initialize(
ingredient,
show_caption: nil,
disable_link: nil,
srcset: nil,
sizes: nil,
picture_options: {},
html_options: {}
)
super(ingredient)
@show_caption = show_caption.nil? ? ingredient.settings.fetch(:show_caption, true) : show_caption
@disable_link = disable_link.nil? ? ingredient.settings.fetch(:disable_link, false) : disable_link
@srcset = srcset.nil? ? ingredient.settings.fetch(:srcset, []) : srcset
@sizes = sizes.nil? ? ingredient.settings.fetch(:sizes, []) : sizes
@picture_options = picture_options || {}
@html_options = html_options || {}
@picture = ingredient.picture
end

def call
return if picture.blank?

output = caption ? img_tag + caption : img_tag

if is_linked?
output = link_to(output, url_for(ingredient.link), {
title: ingredient.link_title.presence,
target: (ingredient.link_target == "blank") ? "_blank" : nil,
data: {link_target: ingredient.link_target.presence}
})
end

if caption
content_tag(:figure, output, {class: ingredient.css_class.presence}.merge(html_options))
else
output
end
end

private

def caption
return unless show_caption?

@_caption ||= content_tag(:figcaption, ingredient.caption)
end

def src
ingredient.picture_url(picture_options)
end

def img_tag
@_img_tag ||= image_tag(
src, {
alt: alt_text,
title: ingredient.title.presence,
class: caption ? nil : ingredient.css_class.presence,
srcset: srcset_options.join(", ").presence,
sizes: sizes.join(", ").presence
}.merge(caption ? {} : html_options)
)
end

def show_caption?
show_caption && ingredient.caption.present?
end

def is_linked?
!disable_link && ingredient.link.present?
end

def srcset_options
srcset.map do |size|
url = ingredient.picture_url(size: size)
width, height = size.split("x")
width.present? ? "#{url} #{width}w" : "#{url} #{height}h"
end
end

def alt_text
ingredient.alt_tag.presence || html_options.delete(:alt) || ingredient.picture.name&.humanize
end
end
end
end
22 changes: 22 additions & 0 deletions app/components/alchemy/ingredients/richtext_view.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module Alchemy
module Ingredients
class RichtextView < BaseView
attr_reader :plain_text

# @param ingredient [Alchemy::Ingredient]
# @param plain_text [Boolean] (false) Whether to show as plain text or with markup
def initialize(ingredient, plain_text: nil, html_options: {})
super(ingredient)
@plain_text = plain_text.nil? ? ingredient.settings.fetch(:plain_text, false) : plain_text
end

def call
if plain_text
ingredient.stripped_body
else
value.to_s.html_safe
end
end
end
end
end
6 changes: 6 additions & 0 deletions app/components/alchemy/ingredients/select_view.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module Alchemy
module Ingredients
class SelectView < BaseView
end
end
end
Loading

0 comments on commit 4a04814

Please sign in to comment.