diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index b0db7459..d6f0af67 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -632,3 +632,33 @@ $bezier: cubic-bezier(0.75, 0, 0.25, 1); } } } + +// https://getbootstrap.com/docs/5.1/components/placeholders/ +.placeholder { + display: inline-block; + min-height: $spacer; + cursor: wait; + vertical-align: middle; + opacity: .5; + background-color: $grey; + animation: placeholder-glow 2s ease-in-out infinite; +} + +.placeholder-glow { + .placeholder { + -webkit-animation: placeholder-glow 2s ease-in-out infinite; + animation: placeholder-glow 2s ease-in-out infinite; + } + + @-webkit-keyframes placeholder-glow { + 50% { + opacity: .2; + } + } + + @keyframes placeholder-glow { + 50% { + opacity: .2; + } + } +} diff --git a/app/javascript/controllers/array_controller.js b/app/javascript/controllers/array_controller.js index 66cc2290..19d00ccd 100644 --- a/app/javascript/controllers/array_controller.js +++ b/app/javascript/controllers/array_controller.js @@ -1,7 +1,7 @@ import { Controller } from "stimulus"; export default class extends Controller { - static targets = ["item", "search", "current"]; + static targets = ["item", "search", "current", "placeholder"]; connect() { // TODO: Stimulus >1 @@ -104,12 +104,19 @@ export default class extends Controller { this.originalValue.push(itemTarget.dataset.value); this.newArrayValueURL.searchParams.set("value", itemTarget.dataset.value); + const placeholder = this.placeholderTarget.content.firstElementChild.cloneNode(true); + + this.currentTarget.appendChild(placeholder); + // TODO: Renderizarlas todas juntas fetch(this.newArrayValueURL) .then((response) => response.text()) - .then((body) => - this.currentTarget.insertAdjacentHTML("beforeend", body), - ); + .then((body) => { + const template = document.createElement("template"); + template.innerHTML = body; + + placeholder.replaceWith(template.content.firstElementChild); + }); } // TODO: Stimulus >1 diff --git a/app/views/posts/attributes/_new_array.haml b/app/views/posts/attributes/_new_array.haml index b4407c0d..71c409a2 100644 --- a/app/views/posts/attributes/_new_array.haml +++ b/app/views/posts/attributes/_new_array.haml @@ -6,25 +6,29 @@ form_id = "form-#{Nanoid.generate}" %div{ data: { controller: 'modal array enter', 'array-original-value': metadata.value.to_json, 'array-new-array-value': site_posts_new_array_value_path(site) } } + %template{ data: { target: 'array.placeholder' } } + .col.mb-3{ 'aria-hidden': 'true' } + %span.placeholder.w-100 + .form-group = hidden_field_tag name, '' - = label_tag id, post_label_t(attribute, post: post) - -# Mostramos la lista de valores actuales. + .d-flex.align-items-center.justify-content-between + = label_tag id, post_label_t(attribute, post: post) + = render 'bootstrap/btn', content: t('.edit'), action: 'modal#show' + -# Mostramos la lista de valores actuales. - Al aceptar el modal, se vacía el listado y se completa en base a - renderizaciones con HTMX. Para poder hacer eso, tenemos que poder - acceder a todos los items dentro del modal (como array.item) y - enviar el valor al endpoint que devuelve uno por uno. Esto lo - tenemos disponible en Stimulus, pero queremos usar HTMX o técnica - similar para poder renderizar del lado del servidor. + Al aceptar el modal, se vacía el listado y se completa en base a + renderizaciones con HTMX. Para poder hacer eso, tenemos que poder + acceder a todos los items dentro del modal (como array.item) y + enviar el valor al endpoint que devuelve uno por uno. Esto lo + tenemos disponible en Stimulus, pero queremos usar HTMX o técnica + similar para poder renderizar del lado del servidor. - Para poder cancelar, mantenemos el estado original y desactivamos - o activamos los ítemes según estén incluidos en esa lista o no. - .row.row-cols-1.row-cols-md-2{ data: { target: 'array.current' } } - - metadata.value.sort_by(&:remove_diacritics).each do |value| - = render 'posts/new_array_value', value: value - - = render 'bootstrap/btn', content: t('.edit'), action: 'modal#show' + Para poder cancelar, mantenemos el estado original y desactivamos + o activamos los ítemes según estén incluidos en esa lista o no. + .row.row-cols-1.row-cols-md-2.no-gutters.placeholder-glow{ data: { target: 'array.current' } } + - metadata.value.sort_by(&:remove_diacritics).each do |value| + = render 'posts/new_array_value', value: value = render 'bootstrap/modal', id: id, modal_content_attributes: { class: 'h-100' }, hide_actions: ['array#cancel'] do - content_for :"#{id}_header" do diff --git a/app/views/posts/attributes/_new_belongs_to.haml b/app/views/posts/attributes/_new_belongs_to.haml index d30d22dd..afbc8bdd 100644 --- a/app/views/posts/attributes/_new_belongs_to.haml +++ b/app/views/posts/attributes/_new_belongs_to.haml @@ -19,25 +19,30 @@ value_list_id = "#{id}_body" %div{ id: modal_id, data: { controller: 'modal array', 'array-original-value': metadata.value.to_json, 'array-new-array-value': site_posts_new_related_post_path(site) } } + %template{ data: { target: 'array.placeholder' } } + .col.p-3{ 'aria-hidden': 'true' } + %span.placeholder.w-100 + .form-group = hidden_field_tag name, '' - = label_tag id, post_label_t(attribute, post: post) - -# Mostramos la lista de valores actuales. + .d-flex.align-items-center.justify-content-between + = label_tag id, post_label_t(attribute, post: post) + = render 'bootstrap/btn', content: t('.edit'), action: 'modal#show' - Al aceptar el modal, se vacía el listado y se completa en base a - renderizaciones con HTMX. Para poder hacer eso, tenemos que poder - acceder a todos los items dentro del modal (como array.item) y - enviar el valor al endpoint que devuelve uno por uno. Esto lo - tenemos disponible en Stimulus, pero queremos usar HTMX o técnica - similar para poder renderizar del lado del servidor. + -# Mostramos la lista de valores actuales. - Para poder cancelar, mantenemos el estado original y desactivamos - o activamos los ítemes según estén incluidos en esa lista o no. - .row.row-cols-3.row-cols-md-4{ data: { target: 'array.current' } } - - metadata.values.slice(*metadata.value).each do |value| - = render 'posts/new_array_value', value: value + Al aceptar el modal, se vacía el listado y se completa en base a + renderizaciones con HTMX. Para poder hacer eso, tenemos que poder + acceder a todos los items dentro del modal (como array.item) y + enviar el valor al endpoint que devuelve uno por uno. Esto lo + tenemos disponible en Stimulus, pero queremos usar HTMX o técnica + similar para poder renderizar del lado del servidor. - = render 'bootstrap/btn', content: t('.edit'), action: 'modal#show' + Para poder cancelar, mantenemos el estado original y desactivamos + o activamos los ítemes según estén incluidos en esa lista o no. + .row.row-cols-3.row-cols-md-4.no-gutters.placeholder-glow{ data: { target: 'array.current' } } + - metadata.values.slice(*metadata.value).each do |value| + = render 'posts/new_array_value', value: value = render 'bootstrap/modal', id: id, modal_content_attributes: { class: 'h-100' }, hide_actions: ['array#cancel'] do - content_for :"#{id}_header" do diff --git a/app/views/posts/attributes/_new_has_many.haml b/app/views/posts/attributes/_new_has_many.haml index e35ef453..143ad2d1 100644 --- a/app/views/posts/attributes/_new_has_many.haml +++ b/app/views/posts/attributes/_new_has_many.haml @@ -19,25 +19,29 @@ value_list_id = "#{id}_body" %div{ id: modal_id, data: { controller: 'modal array', 'array-original-value': metadata.value.to_json, 'array-new-array-value': site_posts_new_related_post_path(site) } } + %template{ data: { target: 'array.placeholder' } } + .col.p-3{ 'aria-hidden': 'true' } + %span.placeholder.w-100 + .form-group = hidden_field_tag name, '' - = label_tag id, post_label_t(attribute, post: post) - -# Mostramos la lista de valores actuales. + .d-flex.align-items-center.justify-content-between + = label_tag id, post_label_t(attribute, post: post) + = render 'bootstrap/btn', content: t('.edit'), action: 'modal#show' + -# Mostramos la lista de valores actuales. - Al aceptar el modal, se vacía el listado y se completa en base a - renderizaciones con HTMX. Para poder hacer eso, tenemos que poder - acceder a todos los items dentro del modal (como array.item) y - enviar el valor al endpoint que devuelve uno por uno. Esto lo - tenemos disponible en Stimulus, pero queremos usar HTMX o técnica - similar para poder renderizar del lado del servidor. + Al aceptar el modal, se vacía el listado y se completa en base a + renderizaciones con HTMX. Para poder hacer eso, tenemos que poder + acceder a todos los items dentro del modal (como array.item) y + enviar el valor al endpoint que devuelve uno por uno. Esto lo + tenemos disponible en Stimulus, pero queremos usar HTMX o técnica + similar para poder renderizar del lado del servidor. - Para poder cancelar, mantenemos el estado original y desactivamos - o activamos los ítemes según estén incluidos en esa lista o no. - .row.row-cols-3.row-cols-md-4{ data: { target: 'array.current' } } - - metadata.values.slice(*metadata.value).each do |value| - = render 'posts/new_array_value', value: value - - = render 'bootstrap/btn', content: t('.edit'), action: 'modal#show' + Para poder cancelar, mantenemos el estado original y desactivamos + o activamos los ítemes según estén incluidos en esa lista o no. + .row.row-cols-3.row-cols-md-4.no-gutters.placeholder-glow{ data: { target: 'array.current' } } + - metadata.values.slice(*metadata.value).each do |value| + = render 'posts/new_array_value', value: value = render 'bootstrap/modal', id: id, modal_content_attributes: { class: 'h-100' }, hide_actions: ['array#cancel'] do - content_for :"#{id}_header" do diff --git a/app/views/posts/attributes/_new_predefined_array.haml b/app/views/posts/attributes/_new_predefined_array.haml index 36f1ae2f..ec251134 100644 --- a/app/views/posts/attributes/_new_predefined_array.haml +++ b/app/views/posts/attributes/_new_predefined_array.haml @@ -8,25 +8,30 @@ form_id = "form-#{Nanoid.generate}" %div{ data: { controller: 'modal array', 'array-original-value': metadata.value.to_json, 'array-new-array-value': site_posts_new_array_value_path(site) } } + %template{ data: { target: 'array.placeholder' } } + .col.mb-3{ 'aria-hidden': 'true' } + %span.placeholder.w-100 + .form-group = hidden_field_tag name, '' - = label_tag id, post_label_t(attribute, post: post) - -# Mostramos la lista de valores actuales. + .d-flex.align-items-center.justify-content-between + = label_tag id, post_label_t(attribute, post: post) + = render 'bootstrap/btn', content: t('.edit'), action: 'modal#show' - Al aceptar el modal, se vacía el listado y se completa en base a - renderizaciones con HTMX. Para poder hacer eso, tenemos que poder - acceder a todos los items dentro del modal (como array.item) y - enviar el valor al endpoint que devuelve uno por uno. Esto lo - tenemos disponible en Stimulus, pero queremos usar HTMX o técnica - similar para poder renderizar del lado del servidor. + -# Mostramos la lista de valores actuales. - Para poder cancelar, mantenemos el estado original y desactivamos - o activamos los ítemes según estén incluidos en esa lista o no. - .row.row-cols-1.row-cols-md-2{ data: { target: 'array.current' } } - - metadata.values.slice(*metadata.value).each_key do |value| - = render 'posts/new_array_value', value: value + Al aceptar el modal, se vacía el listado y se completa en base a + renderizaciones con HTMX. Para poder hacer eso, tenemos que poder + acceder a todos los items dentro del modal (como array.item) y + enviar el valor al endpoint que devuelve uno por uno. Esto lo + tenemos disponible en Stimulus, pero queremos usar HTMX o técnica + similar para poder renderizar del lado del servidor. - = render 'bootstrap/btn', content: t('.edit'), action: 'modal#show' + Para poder cancelar, mantenemos el estado original y desactivamos + o activamos los ítemes según estén incluidos en esa lista o no. + .row.row-cols-1.row-cols-md-2.no-gutters.placeholder-glow{ data: { target: 'array.current' } } + - metadata.values.slice(*metadata.value).each_key do |value| + = render 'posts/new_array_value', value: value = render 'bootstrap/modal', id: id, modal_content_attributes: { class: 'h-100' }, hide_actions: ['array#cancel'] do - content_for :"#{id}_header" do