mirror of
https://github.com/manyfold3d/manyfold.git
synced 2026-10-21 19:22:18 -05:00
135 lines
3.8 KiB
Ruby
135 lines
3.8 KiB
Ruby
class Components::ImageCarousel < Components::Base
|
|
include Phlex::Rails::Helpers::FormWith
|
|
|
|
register_value_helper :policy
|
|
|
|
def initialize(images:)
|
|
@images = images
|
|
end
|
|
|
|
def render?
|
|
!@images.empty?
|
|
end
|
|
|
|
def view_template
|
|
div id: "imageCarousel",
|
|
class: "carousel slide mb-3",
|
|
role: "group",
|
|
data: {
|
|
bs_ride: "carousel",
|
|
controller: "carousel",
|
|
action: "mouseenter->carousel#onEnter mouseleave->carousel#onLeave"
|
|
},
|
|
aria: {
|
|
roledescription: "carousel"
|
|
} do
|
|
if @images.count > 1
|
|
play_pause_control
|
|
end
|
|
div id: "imageCarouselInner",
|
|
class: "carousel-inner",
|
|
aria: {
|
|
atomic: false,
|
|
live: "off"
|
|
} do
|
|
@images.each_with_index do |image, index|
|
|
div class: ((index == 0) ? "carousel-item active" : "carousel-item"),
|
|
role: "group",
|
|
aria: {
|
|
roledescription: "slide",
|
|
label: translate("components.image_carousel.slide_label", index: (index + 1), count: @images.count, name: image.name)
|
|
} do
|
|
img src: model_model_file_path(image.model, image, format: image.extension, derivative: "carousel"),
|
|
alt: image.name,
|
|
class: "d-block w-100 carousel"
|
|
button_overlay(image)
|
|
end
|
|
end
|
|
end
|
|
if @images.count > 1
|
|
slide_indicators
|
|
next_prev_controls
|
|
end
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def play_pause_control
|
|
button id: "rotationControl",
|
|
class: "carousel-control-play btn btn-secondary m-2",
|
|
data: {
|
|
action: "click->carousel#onPauseButton"
|
|
} do
|
|
Icon icon: "pause", label: t("components.image_carousel.play_pause"), id: "rotationControlIcon"
|
|
end
|
|
end
|
|
|
|
def slide_indicators
|
|
div class: "carousel-indicators",
|
|
role: "group",
|
|
aria: {
|
|
label: translate("components.image_carousel.select_slide")
|
|
} do
|
|
@images.each_with_index do |image, index|
|
|
button type: "button",
|
|
data: {
|
|
bs_target: "#imageCarousel",
|
|
bs_slide_to: index
|
|
},
|
|
class: ("active" if index == 0),
|
|
aria: {
|
|
label: translate("components.image_carousel.slide_label", index: (index + 1), count: @images.count, name: image.name),
|
|
current: (index == 0),
|
|
disabled: (index == 0)
|
|
}
|
|
end
|
|
end
|
|
end
|
|
|
|
def next_prev_controls
|
|
button class: "carousel-control-prev",
|
|
type: "button",
|
|
tabindex: -1,
|
|
data: {
|
|
bs_target: "#imageCarousel",
|
|
bs_slide: "prev"
|
|
} do
|
|
span class: "carousel-control-prev-icon", aria: {hidden: true}
|
|
span(class: "visually-hidden") { t("components.image_carousel.previous") }
|
|
end
|
|
button class: "carousel-control-next",
|
|
type: "button",
|
|
tabindex: -1,
|
|
data: {
|
|
bs_target: "#imageCarousel",
|
|
bs_slide: "next"
|
|
} do
|
|
span class: "carousel-control-next-icon", aria: {hidden: true}
|
|
span(class: "visually-hidden") { t("components.image_carousel.next") }
|
|
end
|
|
end
|
|
|
|
def button_overlay(image)
|
|
div class: "carousel-caption d-none d-md-block" do
|
|
if image.model.preview_file != image && policy(image).edit?
|
|
form_with model: image.model, class: "d-inline" do |form|
|
|
form.hidden_field :preview_file_id, value: image.id
|
|
form.button t("models.file.set_as_preview"), class: "btn btn-sm btn-outline-warning"
|
|
end
|
|
end
|
|
if policy(image).destroy?
|
|
a href: model_model_file_path(image.model, image),
|
|
tabindex: 0,
|
|
class: "btn btn-sm btn-outline-danger",
|
|
data: {
|
|
method: "delete",
|
|
confirm: translate("model_files.destroy.confirm")
|
|
} do
|
|
Icon(icon: "trash", label: t("general.delete"))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|