Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use view_component for ingredient views #2465

Merged
merged 19 commits into from
May 24, 2023
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
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)
tvdeyen marked this conversation as resolved.
Show resolved Hide resolved
@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 || {}
tvdeyen marked this conversation as resolved.
Show resolved Hide resolved
@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