From 9e95dedb5c5b09644f12b3452ce9fc438541a5ef Mon Sep 17 00:00:00 2001 From: f Date: Fri, 17 May 2024 14:53:10 -0300 Subject: [PATCH 01/10] =?UTF-8?q?feat:=20vamos=20a=20usar=20nanoid=20para?= =?UTF-8?q?=20generar=20ids=20=C3=BAnicos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Gemfile | 1 + Gemfile.lock | 2 ++ 2 files changed, 3 insertions(+) diff --git a/Gemfile b/Gemfile index 5714b981..30794e83 100644 --- a/Gemfile +++ b/Gemfile @@ -85,6 +85,7 @@ gem 'rubanok' gem 'after_commit_everywhere', '~> 1.0' gem 'aasm' gem 'que-web' +gem 'nanoid' # database gem 'hairtrigger' diff --git a/Gemfile.lock b/Gemfile.lock index 7f5284ef..db6b892d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -373,6 +373,7 @@ GEM multi_xml (0.6.0) mustermann (3.0.0) ruby2_keywords (~> 0.0.1) + nanoid (2.0.0) net-imap (0.4.9) date net-protocol @@ -677,6 +678,7 @@ DEPENDENCIES memory_profiler mini_magick mobility + nanoid net-ssh nokogiri pg From 5f5026bccabdd97f970c845bddc6e355d0b7fc6e Mon Sep 17 00:00:00 2001 From: f Date: Fri, 17 May 2024 14:57:13 -0300 Subject: [PATCH 02/10] =?UTF-8?q?fix:=20solo=20usar=20fuertecita=20dentro?= =?UTF-8?q?=20de=20los=20dise=C3=B1os?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/assets/stylesheets/application.scss | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 4d1d0848..68b610bc 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -318,13 +318,13 @@ svg { } } -.custom-control-label { - font-weight: bold; -} - .designs { .design { margin-top: 1rem; + + .custom-control-label { + font-weight: bold; + } } } From c75deaf030f11bcae796e5110bc649a3869766cb Mon Sep 17 00:00:00 2001 From: f Date: Fri, 17 May 2024 14:59:23 -0300 Subject: [PATCH 03/10] feat: poder modificar atributos del custom-input --- app/views/bootstrap/_custom_checkbox.haml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/views/bootstrap/_custom_checkbox.haml b/app/views/bootstrap/_custom_checkbox.haml index 0c3ff3a6..a2cf6c27 100644 --- a/app/views/bootstrap/_custom_checkbox.haml +++ b/app/views/bootstrap/_custom_checkbox.haml @@ -1,6 +1,9 @@ - help_id = "#{id}_help" +- checkbox_attributes = local_assigns.slice(:id, :type, :name, :value, :required, :checked) +- checkbox_attributes[:type] ||= 'checkbox' .custom-control.custom-checkbox - %input.custom-control-input{ id: id, type: 'checkbox', name: name, value: value, required: required } + %input.custom-control-input{ **checkbox_attributes } %label.custom-control-label{ for: id, aria: { describedby: help_id } }= content - %small.form-text.text-muted{ id: help_id }= yield + - if (block = yield).present? + %small.form-text.text-muted{ id: help_id }= block From 8fe964686bfc7c46e5b89636c9fd3b47d23dc6e7 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 17 May 2024 15:00:08 -0300 Subject: [PATCH 04/10] feat: eliminar tildes de una string, sin transliterar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit usamos esto porque es más rápido y podemos tener un proceso similar en js sin implementar transliteración --- app/lib/core_extensions/string/remove_diacritics.rb | 12 ++++++++++++ config/initializers/core_extensions.rb | 1 + 2 files changed, 13 insertions(+) create mode 100644 app/lib/core_extensions/string/remove_diacritics.rb diff --git a/app/lib/core_extensions/string/remove_diacritics.rb b/app/lib/core_extensions/string/remove_diacritics.rb new file mode 100644 index 00000000..679db13d --- /dev/null +++ b/app/lib/core_extensions/string/remove_diacritics.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module CoreExtensions + module String + # Elimina tildes + module RemoveDiacritics + def remove_diacritics + unicode_normalize(:nfd).gsub(/[^\x00-\x7F]/, '') + end + end + end +end diff --git a/config/initializers/core_extensions.rb b/config/initializers/core_extensions.rb index 7d1eab9e..6861da45 100644 --- a/config/initializers/core_extensions.rb +++ b/config/initializers/core_extensions.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true String.include CoreExtensions::String::StripTags +String.include CoreExtensions::String::RemoveDiacritics Jekyll::Document.include CoreExtensions::Jekyll::Document::Path Jekyll::DataReader.include Jekyll::Readers::DataReaderDecorator From ee459b2d4e75980eba343d1686599667eff7a427 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 17 May 2024 15:06:44 -0300 Subject: [PATCH 05/10] feat: modal de boostrap 4.6 --- app/assets/stylesheets/application.scss | 1 + .../controllers/modal_controller.js | 40 +++++++++++++++++++ app/views/bootstrap/_modal.haml | 38 ++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 app/javascript/controllers/modal_controller.js create mode 100644 app/views/bootstrap/_modal.haml diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 68b610bc..7d9c8c9d 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -20,6 +20,7 @@ $form-feedback-valid-color: $black; $form-feedback-invalid-color: $magenta; $form-feedback-icon-valid-color: $black; $component-active-bg: $magenta; +$zindex-modal-backdrop: 0; $spacers: ( 2-plus: 0.75rem diff --git a/app/javascript/controllers/modal_controller.js b/app/javascript/controllers/modal_controller.js new file mode 100644 index 00000000..3a614b80 --- /dev/null +++ b/app/javascript/controllers/modal_controller.js @@ -0,0 +1,40 @@ +import { Controller } from "stimulus"; + +export default class extends Controller { + static targets = ["modal", "backdrop"]; + + show(event = undefined) { + event?.preventDefault(); + + this.modalTarget.style.display = "block"; + this.backdropTarget.style.display = "block"; + this.modalTarget.setAttribute("role", "dialog"); + this.modalTarget.setAttribute("aria-modal", true); + this.modalTarget.removeAttribute("aria-hidden"); + + window.document.body.classList.add("modal-open"); + + setTimeout(() => { + this.modalTarget.classList.add("show"); + this.backdropTarget.classList.add("show"); + }, 1); + } + + hide(event = undefined) { + event?.preventDefault(); + + this.backdropTarget.classList.remove("show"); + this.modalTarget.classList.remove("show"); + + this.modalTarget.setAttribute("aria-hidden", true); + this.modalTarget.removeAttribute("role"); + this.modalTarget.removeAttribute("aria-modal"); + + setTimeout(() => { + this.modalTarget.style.display = ""; + this.backdropTarget.style.display = ""; + }, 500); + + window.document.body.classList.remove("modal-open"); + } +} diff --git a/app/views/bootstrap/_modal.haml b/app/views/bootstrap/_modal.haml new file mode 100644 index 00000000..b57fc94e --- /dev/null +++ b/app/views/bootstrap/_modal.haml @@ -0,0 +1,38 @@ +-# + # Modal + + @see {https://getbootstrap.com/docs/4.6/components/modal/} + @see {https://github.com/bullet-train-co/nice_partials/issues/99} + @param :id [String] El ID del modal + @param :modal_content_attributes [Hash] Atributos para el contenido del modal + @param :hide_actions [Array] Acciones al ocultar el modal + @yield :ID_body Contenido + @yield :ID_header Contenido del header (opcional) + @yield :ID_footer Contenido del pie (opcional) + @example + = render 'bootstrap/modal', id: 'algo' do |partial| + - content_for :algo_header do + = 'título' + - content_for :algo_body do + = 'contenido' + - content_for :algo_footer do + = 'pie' + +- local_assigns[:hide_actions] ||= [] +- local_assigns[:hide_actions] << 'click->modal#hide' +- local_assigns[:modal_content_attributes] ||= {} + +.modal.fade{ tabindex: -1, aria: { hidden: 'true' }, data: { target: 'modal.modal' } } + .modal-backdrop.fade{ data: { target: 'modal.backdrop', action: local_assigns[:hide_actions].join(' ') } } + .modal-dialog.modal-dialog-scrollable.modal-dialog-centered + .modal-content{ **local_assigns[:modal_content_attributes] } + - if (header = yield(:"#{id}_header")).present? + .modal-header= header + + .modal-body= yield(:"#{id}_body") + + .modal-footer.flex-nowrap + - if (footer = yield(:"#{id}_footer")) + = footer + - else + %button.btn.btn-secondary.m-0{ type: 'button', data: { action: 'modal#hide' } }= t('.close') From 7dbe12ed66c851b3f3b3de5e9b4bd1d38c0aed26 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 17 May 2024 15:07:22 -0300 Subject: [PATCH 06/10] fix: no permitir que htmx haga peticiones fuera del panel --- app/javascript/packs/application.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js index e10e2b5d..c523b0f0 100644 --- a/app/javascript/packs/application.js +++ b/app/javascript/packs/application.js @@ -42,3 +42,4 @@ Turbolinks.start() ActiveStorage.start() window.htmx = require('htmx.org/dist/htmx.js') +window.htmx.config.selfRequestsOnly = true; From 76de2e543e1cc0562937e89545c2e57909481e31 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 17 May 2024 15:17:47 -0300 Subject: [PATCH 07/10] =?UTF-8?q?feat:=20un=20bot=C3=B3n=20accionable?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/bootstrap/_btn.haml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 app/views/bootstrap/_btn.haml diff --git a/app/views/bootstrap/_btn.haml b/app/views/bootstrap/_btn.haml new file mode 100644 index 00000000..22f60b3e --- /dev/null +++ b/app/views/bootstrap/_btn.haml @@ -0,0 +1,12 @@ +-# + Un botón + + @param :content [String] Contenido + @param :action [String] Acción de Stimulus + @param :target [String] Objetivo de Stimulus + @param [Hash] Atributos en bruto, con mayor prioridad que action y target +- attributes = local_assigns.to_h.except(:content) +- attributes[:data] ||= {} +- attributes[:data][:action] ||= local_assigns[:action] +- attributes[:data][:target] ||= local_assigns[:target] +%button.btn.btn-secondary{ type: 'button', **attributes }= content From ae06e3e788a8c5f92ccd735bc81baa1db7e309e9 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 17 May 2024 15:24:08 -0300 Subject: [PATCH 08/10] =?UTF-8?q?feat:=20redise=C3=B1ar=20arrays=20#15068?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/posts_controller.rb | 17 +++ .../controllers/array_controller.js | 120 ++++++++++++++++++ app/javascript/etc/htmx_abort.js | 4 + app/models/metadata_new_array.rb | 6 + app/views/layouts/application.html.haml | 1 + app/views/posts/_new_array_value.haml | 2 + app/views/posts/attributes/_new_array.haml | 58 +++++++++ app/views/posts/new_array.haml | 8 ++ app/views/posts/new_array_value.haml | 1 + config/locales/en.yml | 9 ++ config/locales/es.yml | 9 ++ config/routes.rb | 4 + 12 files changed, 239 insertions(+) create mode 100644 app/javascript/controllers/array_controller.js create mode 100644 app/models/metadata_new_array.rb create mode 100644 app/views/posts/_new_array_value.haml create mode 100644 app/views/posts/attributes/_new_array.haml create mode 100644 app/views/posts/new_array.haml create mode 100644 app/views/posts/new_array_value.haml diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index 057c3068..f241dfb1 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -15,6 +15,23 @@ class PostsController < ApplicationController { locale: locale } end + # @todo Mover a tu propio scope + def new_array + @value = params.require(:value).strip + @name = params.require(:name).strip + id = params.require(:id).strip + + headers['HX-Trigger-After-Swap'] = 'htmx:resetForm' + + render layout: false + end + + def new_array_value + @value = params.require(:value).strip + + render layout: false + end + def index authorize Post diff --git a/app/javascript/controllers/array_controller.js b/app/javascript/controllers/array_controller.js new file mode 100644 index 00000000..66cc2290 --- /dev/null +++ b/app/javascript/controllers/array_controller.js @@ -0,0 +1,120 @@ +import { Controller } from "stimulus"; + +export default class extends Controller { + static targets = ["item", "search", "current"]; + + connect() { + // TODO: Stimulus >1 + this.newArrayValueURL = new URL(window.location.origin); + this.newArrayValueURL.pathname = this.element.dataset.arrayNewArrayValue; + this.originalValue = JSON.parse(this.element.dataset.arrayOriginalValue); + } + + /* + * Al eliminar el ítem, buscamos por su ID y lo eliminamos del + * documento. + */ + remove(event) { + // TODO: Stimulus >1 + event.preventDefault(); + + this.itemTargets + .find((x) => x.id === event.target.dataset.removeTargetParam) + ?.remove(); + } + + /* + * Al buscar, eliminamos las tildes y mayúsculas para no depender de + * cómo se escribió. + * + * Luego buscamos eso en el valor limpio, ignorando los items que ya + * están activados. + * + * Si el término de búsqueda está vacío, volvemos a la lista original. + */ + search(event) { + const needle = this.searchTarget.value + .normalize("NFD") + .replace(/[\u0300-\u036f]/g, "") + .toLowerCase() + .trim(); + + if (needle) { + for (const itemTarget of this.itemTargets) { + itemTarget.style.display = + itemTarget.querySelector("input")?.checked || + itemTarget.dataset.searchableValue.includes(needle) + ? "" + : "none"; + } + } else { + for (const itemTarget of this.itemTargets) { + itemTarget.style.display = ""; + } + } + } + + /* + * Obtiene el input de un elemento + * + * @param [HTMLElement] + * @return [HTMLElement,nil] + */ + inputFrom(target) { + if (target.tagName === "INPUT") return target; + + return target.querySelector("input"); + } + + /* + * Detecta si el item es o contiene un checkbox/radio activado. + * + * @param [HTMLElement] + * @return [Bool] + */ + isChecked(itemTarget) { + return this.inputFrom(itemTarget)?.checked || false; + } + + /* + * Al cancelar, se vuelve al estado original de la lista + */ + cancel(event) { + for (const itemTarget of this.itemTargets) { + const input = this.inputFrom(itemTarget); + + input.checked = this.originalValue.includes(itemTarget.dataset.value); + } + } + + /* + * Al aceptar, se envía todo el listado de valores nuevos al _backend_ + * para que devuelva la representación de cada ítem en HTML. Además, + * se guarda el nuevo valor como la lista original, para la próxima + * cancelación. + */ + accept(event) { + this.currentTarget.innerHTML = ""; + this.originalValue = []; + + for (const itemTarget of this.itemTargets) { + if (!itemTarget.dataset.value) continue; + if (!this.isChecked(itemTarget)) continue; + + this.originalValue.push(itemTarget.dataset.value); + this.newArrayValueURL.searchParams.set("value", itemTarget.dataset.value); + + // TODO: Renderizarlas todas juntas + fetch(this.newArrayValueURL) + .then((response) => response.text()) + .then((body) => + this.currentTarget.insertAdjacentHTML("beforeend", body), + ); + } + + // TODO: Stimulus >1 + this.element.dataset.arrayOriginalValue = JSON.stringify( + this.originalValue, + ); + } +} diff --git a/app/javascript/etc/htmx_abort.js b/app/javascript/etc/htmx_abort.js index 308d0315..75e497ba 100644 --- a/app/javascript/etc/htmx_abort.js +++ b/app/javascript/etc/htmx_abort.js @@ -5,3 +5,7 @@ document.addEventListener("turbolinks:click", () => { window.htmx.trigger(hx, "htmx:abort"); } }); + +document.addEventListener("htmx:resetForm", (event) => { + event.target.reset(); +}); diff --git a/app/models/metadata_new_array.rb b/app/models/metadata_new_array.rb new file mode 100644 index 00000000..a76ff9f2 --- /dev/null +++ b/app/models/metadata_new_array.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +# Implementa la nueva interfaz de +class MetadataNewArray < MetadataArray + +end diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index eaa15eb4..65d3f777 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -25,6 +25,7 @@ = render 'layouts/breadcrumb' = render 'layouts/flash' + = yield(:post_form) = yield - if flash[:js] diff --git a/app/views/posts/_new_array_value.haml b/app/views/posts/_new_array_value.haml new file mode 100644 index 00000000..75c5bf4d --- /dev/null +++ b/app/views/posts/_new_array_value.haml @@ -0,0 +1,2 @@ +.col + %p= value diff --git a/app/views/posts/attributes/_new_array.haml b/app/views/posts/attributes/_new_array.haml new file mode 100644 index 00000000..79ba22e2 --- /dev/null +++ b/app/views/posts/attributes/_new_array.haml @@ -0,0 +1,58 @@ +-# + Genera un listado de checkboxes entre los que se puede elegir para guardar +- id = "#{base}_#{attribute}" +- name = "#{base}[#{attribute}][]" +- 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) } } + .form-group + = hidden_field_tag name, '' + = label_tag id, post_label_t(attribute, post: post) + -# 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. + + 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' + + = render 'bootstrap/modal', id: id, modal_content_attributes: { class: 'h-100' }, hide_actions: ['array#cancel'] do + - content_for :"#{id}_header" do + .form-group.flex-grow-1.mb-0 + = label_tag id, post_label_t(attribute, post: post) + %input.form-control{data: { target: 'array.search', action: 'input->array#search' }, type: 'search', placeholder: t('.filter') } + + - content_for :"#{id}_body" do + .form-group.mb-0{ id: "#{id}_body" } + -# Eliminamos las tildes para poder buscar independientemente de cómo se escriba + - metadata.values.sort_by(&:remove_diacritics).each do |value| + .mb-2{ data: { target: 'array.item', 'searchable-value': value.remove_diacritics.downcase, value: value } } + = render 'bootstrap/custom_checkbox', name: name, id: "value-#{Nanoid.generate}", value: value, checked: metadata.value.include?(value), content: value + + - content_for :"#{id}_footer" do + .input-group.w-auto.flex-grow-1.my-0 + %input.form-control{form: form_id, name: 'value', type: 'text', placeholder: t('.add_new')} + .input-group-append + = render 'bootstrap/btn', content: t('.add'), form: form_id, type: 'submit', class: 'mb-0 mr-0' + = render 'bootstrap/btn', content: t('.accept'), action: 'array#accept modal#hide', class: 'm-0 mr-1' + = render 'bootstrap/btn', content: t('.cancel'), action: 'array#cancel modal#hide', class: 'm-0' + + -# Los formularios para HTMX se colocan por fuera del formulario + principal, porque HTML5 no soporta formularios anidados. Los campos + quedan unidos al formulario por su atributo `id`. + + Al enviar el formulario se obtiene una nueva opción con el valor + y se la agrega al final del listado. + - content_for :post_form do + %form{ id: form_id, 'hx-get': site_posts_new_array_path(site), 'hx-target': "##{id}_body", 'hx-swap': 'beforeend' } + %input{ type: 'hidden', name: 'name', value: name } + %input{ type: 'hidden', name: 'id', value: form_id } diff --git a/app/views/posts/new_array.haml b/app/views/posts/new_array.haml new file mode 100644 index 00000000..81cdcdea --- /dev/null +++ b/app/views/posts/new_array.haml @@ -0,0 +1,8 @@ +- item_id = "item-#{Nanoid.generate}" + +.mb-2{ id: item_id, data: { target: 'array.item', 'searchable-value': @value.remove_diacritics.downcase, value: @value } } + .d-flex.flex-row.flex-wrap + .flex-grow-1 + = render 'bootstrap/custom_checkbox', name: @name, id: "value-#{Nanoid.generate}", value: @value, checked: true, content: @value + %div + %button.btn.btn-sm.m-0{ data: { action: 'array#remove', 'remove-target-param': item_id }}= t('.remove') diff --git a/app/views/posts/new_array_value.haml b/app/views/posts/new_array_value.haml new file mode 100644 index 00000000..c71ed3b5 --- /dev/null +++ b/app/views/posts/new_array_value.haml @@ -0,0 +1 @@ += render 'posts/new_array_value', value: @value diff --git a/config/locales/en.yml b/config/locales/en.yml index 5e9a2377..88b1db19 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -721,7 +721,16 @@ en: save_draft: 'Save as draft' invalid_help: 'Some fields need attention! Please search for the fields marked as invalid.' sending_help: Saving, please wait... + new_array: + remove: "Remove" attributes: + new_array: + edit: "Edit" + filter: "Start typing to filter..." + add_new: "Add new option" + add: "Add" + accept: "Accept" + cancel: "Cancel" add: Add lang: label: Language diff --git a/config/locales/es.yml b/config/locales/es.yml index a07b3799..4945c19f 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -729,7 +729,16 @@ es: save_draft: 'Guardar como borrador' invalid_help: '¡Te faltan completar algunos campos! Busca los que estén marcados como inválidos' sending_help: Guardando, por favor espera... + new_array: + remove: "Eliminar" attributes: + new_array: + edit: "Editar" + filter: "Empezá a escribir para filtrar..." + add_new: "Agregar nueva opción" + add: "Agregar" + accept: "Aceptar" + cancel: "Cancelar" add: Agregar lang: label: Idioma diff --git a/config/routes.rb b/config/routes.rb index 9d5c974a..eb20edce 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -99,6 +99,10 @@ Rails.application.routes.draw do nested do scope '/(:locale)', constraint: /[a-z]{2}(-[A-Z]{2})?/ do post :'posts/reorder', to: 'posts#reorder' + + get :'posts/new_array', to: 'posts#new_array' + get :'posts/new_array_value', to: 'posts#new_array_value' + resources :posts do get 'p/:page', action: :index, on: :collection get :preview, to: 'posts#preview' From b3a1673795ed738404d66c375b336cd8ff5cc841 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 17 May 2024 15:30:25 -0300 Subject: [PATCH 09/10] chore: linting --- app/models/metadata_new_array.rb | 3 +-- app/views/bootstrap/_btn.haml | 9 +++++---- app/views/bootstrap/_custom_checkbox.haml | 7 ++++--- app/views/bootstrap/_modal.haml | 7 ++++--- app/views/posts/attributes/_new_array.haml | 11 ++++++----- app/views/posts/new_array.haml | 2 +- 6 files changed, 21 insertions(+), 18 deletions(-) diff --git a/app/models/metadata_new_array.rb b/app/models/metadata_new_array.rb index a76ff9f2..65993be2 100644 --- a/app/models/metadata_new_array.rb +++ b/app/models/metadata_new_array.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true -# Implementa la nueva interfaz de +# Implementa la nueva interfaz de gestión de valores class MetadataNewArray < MetadataArray - end diff --git a/app/views/bootstrap/_btn.haml b/app/views/bootstrap/_btn.haml index 22f60b3e..1bbebb26 100644 --- a/app/views/bootstrap/_btn.haml +++ b/app/views/bootstrap/_btn.haml @@ -5,8 +5,9 @@ @param :action [String] Acción de Stimulus @param :target [String] Objetivo de Stimulus @param [Hash] Atributos en bruto, con mayor prioridad que action y target -- attributes = local_assigns.to_h.except(:content) -- attributes[:data] ||= {} -- attributes[:data][:action] ||= local_assigns[:action] -- attributes[:data][:target] ||= local_assigns[:target] +:ruby + attributes = local_assigns.to_h.except(:content) + attributes[:data] ||= {} + attributes[:data][:action] ||= local_assigns[:action] + attributes[:data][:target] ||= local_assigns[:target] %button.btn.btn-secondary{ type: 'button', **attributes }= content diff --git a/app/views/bootstrap/_custom_checkbox.haml b/app/views/bootstrap/_custom_checkbox.haml index a2cf6c27..c8cd1b41 100644 --- a/app/views/bootstrap/_custom_checkbox.haml +++ b/app/views/bootstrap/_custom_checkbox.haml @@ -1,6 +1,7 @@ -- help_id = "#{id}_help" -- checkbox_attributes = local_assigns.slice(:id, :type, :name, :value, :required, :checked) -- checkbox_attributes[:type] ||= 'checkbox' +:ruby + help_id = "#{id}_help" + checkbox_attributes = local_assigns.slice(:id, :type, :name, :value, :required, :checked) + checkbox_attributes[:type] ||= 'checkbox' .custom-control.custom-checkbox %input.custom-control-input{ **checkbox_attributes } diff --git a/app/views/bootstrap/_modal.haml b/app/views/bootstrap/_modal.haml index b57fc94e..f6dafc2a 100644 --- a/app/views/bootstrap/_modal.haml +++ b/app/views/bootstrap/_modal.haml @@ -18,9 +18,10 @@ - content_for :algo_footer do = 'pie' -- local_assigns[:hide_actions] ||= [] -- local_assigns[:hide_actions] << 'click->modal#hide' -- local_assigns[:modal_content_attributes] ||= {} +:ruby + local_assigns[:hide_actions] ||= [] + local_assigns[:hide_actions] << 'click->modal#hide' + local_assigns[:modal_content_attributes] ||= {} .modal.fade{ tabindex: -1, aria: { hidden: 'true' }, data: { target: 'modal.modal' } } .modal-backdrop.fade{ data: { target: 'modal.backdrop', action: local_assigns[:hide_actions].join(' ') } } diff --git a/app/views/posts/attributes/_new_array.haml b/app/views/posts/attributes/_new_array.haml index 79ba22e2..394345a6 100644 --- a/app/views/posts/attributes/_new_array.haml +++ b/app/views/posts/attributes/_new_array.haml @@ -1,8 +1,9 @@ -# Genera un listado de checkboxes entre los que se puede elegir para guardar -- id = "#{base}_#{attribute}" -- name = "#{base}[#{attribute}][]" -- form_id = "form-#{Nanoid.generate}" +:ruby + id = "#{base}_#{attribute}" + name = "#{base}[#{attribute}][]" + 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) } } .form-group @@ -29,7 +30,7 @@ - content_for :"#{id}_header" do .form-group.flex-grow-1.mb-0 = label_tag id, post_label_t(attribute, post: post) - %input.form-control{data: { target: 'array.search', action: 'input->array#search' }, type: 'search', placeholder: t('.filter') } + %input.form-control{ data: { target: 'array.search', action: 'input->array#search' }, type: 'search', placeholder: t('.filter') } - content_for :"#{id}_body" do .form-group.mb-0{ id: "#{id}_body" } @@ -40,7 +41,7 @@ - content_for :"#{id}_footer" do .input-group.w-auto.flex-grow-1.my-0 - %input.form-control{form: form_id, name: 'value', type: 'text', placeholder: t('.add_new')} + %input.form-control{ form: form_id, name: 'value', type: 'text', placeholder: t('.add_new') } .input-group-append = render 'bootstrap/btn', content: t('.add'), form: form_id, type: 'submit', class: 'mb-0 mr-0' = render 'bootstrap/btn', content: t('.accept'), action: 'array#accept modal#hide', class: 'm-0 mr-1' diff --git a/app/views/posts/new_array.haml b/app/views/posts/new_array.haml index 81cdcdea..62f74854 100644 --- a/app/views/posts/new_array.haml +++ b/app/views/posts/new_array.haml @@ -5,4 +5,4 @@ .flex-grow-1 = render 'bootstrap/custom_checkbox', name: @name, id: "value-#{Nanoid.generate}", value: @value, checked: true, content: @value %div - %button.btn.btn-sm.m-0{ data: { action: 'array#remove', 'remove-target-param': item_id }}= t('.remove') + %button.btn.btn-sm.m-0{ data: { action: 'array#remove', 'remove-target-param': item_id } }= t('.remove') From 87f95cf7e50381c5f63a1781e87c8b10e077bd16 Mon Sep 17 00:00:00 2001 From: f Date: Fri, 17 May 2024 15:35:17 -0300 Subject: [PATCH 10/10] feat: poder ver los cambios hechos --- app/views/posts/attribute_ro/_new_array.haml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 app/views/posts/attribute_ro/_new_array.haml diff --git a/app/views/posts/attribute_ro/_new_array.haml b/app/views/posts/attribute_ro/_new_array.haml new file mode 100644 index 00000000..20a0a545 --- /dev/null +++ b/app/views/posts/attribute_ro/_new_array.haml @@ -0,0 +1,8 @@ +%tr{ id: attribute } + %th= post_label_t(attribute, post: post) + %td + - if metadata.value.respond_to? :each + - metadata.value.each do |v| + %span.badge.badge-primary= v + - else + %span.badge.badge-primary{ lang: locale, dir: dir }= metadata.value