From 5106cdd414b05d1e81689e3fb8efb5fda78b4d01 Mon Sep 17 00:00:00 2001 From: f <f@sutty.nl> Date: Wed, 19 Jun 2024 18:16:49 -0300 Subject: [PATCH 1/5] =?UTF-8?q?fix:=20m=C3=A1s=20arreglos=20tema=20oscuro?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/assets/stylesheets/application.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index ce0b0924..32530ce5 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -26,6 +26,10 @@ $card-bg: var(--background); $card-border-color: var(--card-border-color); $input-bg: var(--background); $input-color: var(--foreground); +$btn-bg-color: var(--btn-bg-color); +$btn-color: var(--btn-color); +$input-group-addon-bg: var(--btn-bg-color); +$custom-file-color: var(--btn-color); $spacers: ( 2-plus: 0.75rem From 6f30727a7b7d0026c24c64d28e59294316f96b03 Mon Sep 17 00:00:00 2001 From: f <f@sutty.nl> Date: Wed, 19 Jun 2024 18:16:58 -0300 Subject: [PATCH 2/5] fix: traducir campo de imagen --- app/assets/stylesheets/application.scss | 14 ++++++++------ app/views/posts/attributes/_file.haml | 1 + app/views/posts/attributes/_image.haml | 1 + 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 32530ce5..d8fe8c9f 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -11,6 +11,14 @@ $colors: ( "magenta": $magenta ); +// TODO: Encontrar la forma de generar esto desde los locales de Rails +$custom-file-text: ( + en: "Browse", + es: "Buscar archivo", + pt: "Buscar arquivo", + pt-BR: "Buscar arquivo" +); + // Redefinir variables de Bootstrap $primary: $magenta; $secondary: $black; @@ -111,12 +119,6 @@ $sizes: ( } } -// TODO: Encontrar la forma de generar esto desde los locales de Rails -$custom-file-text: ( - en: 'Browse', - es: 'Buscar archivo' -); - @font-face { font-family: 'Saira'; font-style: normal; diff --git a/app/views/posts/attributes/_file.haml b/app/views/posts/attributes/_file.haml index 20c27399..007f6b9f 100644 --- a/app/views/posts/attributes/_file.haml +++ b/app/views/posts/attributes/_file.haml @@ -26,6 +26,7 @@ = file_field(*field_name_for(base, attribute, :path), **field_options(attribute, metadata, required: (metadata.required && !metadata.path?)), class: "custom-file-input #{invalid(post, attribute)}", + lang: locale, data: { target: 'file-preview.input', action: 'file-preview#update' }) = label_tag "#{base}_#{attribute}_path", post_label_t(attribute, :path, post: post), class: 'custom-file-label' diff --git a/app/views/posts/attributes/_image.haml b/app/views/posts/attributes/_image.haml index 241a78e8..03d9d15f 100644 --- a/app/views/posts/attributes/_image.haml +++ b/app/views/posts/attributes/_image.haml @@ -23,6 +23,7 @@ **field_options(attribute, metadata, required: (metadata.required && !metadata.path?)), class: "custom-file-input #{invalid(post, attribute)}", accept: ActiveStorage.web_image_content_types.join(','), + lang: locale, data: { target: 'file-preview.input', action: 'file-preview#update' }) = label_tag "#{base}_#{attribute}_path", post_label_t(attribute, :path, post: post), class: 'custom-file-label' From e2af1f215ac389e6ae87e1d4f3c5546992adfc8f Mon Sep 17 00:00:00 2001 From: f <f@sutty.nl> Date: Wed, 19 Jun 2024 18:19:07 -0300 Subject: [PATCH 3/5] feat: las notificaciones se manejan con eventos --- .../controllers/form_validation_controller.js | 37 +++++++--------- .../controllers/notification_controller.js | 43 +++++++++++++++++++ app/views/posts/_form.haml | 14 ++++-- app/views/posts/_submit.haml | 12 +----- app/views/posts/_validation.haml | 16 +++++++ config/locales/en.yml | 5 ++- config/locales/es.yml | 7 ++- 7 files changed, 96 insertions(+), 38 deletions(-) create mode 100644 app/javascript/controllers/notification_controller.js create mode 100644 app/views/posts/_validation.haml diff --git a/app/javascript/controllers/form_validation_controller.js b/app/javascript/controllers/form_validation_controller.js index c9817e27..85e7bb86 100644 --- a/app/javascript/controllers/form_validation_controller.js +++ b/app/javascript/controllers/form_validation_controller.js @@ -3,6 +3,16 @@ import { Controller } from "stimulus"; export default class extends Controller { static targets = ["invalid", "submitting"]; + // @todo Stimulus >1 + get submittingIdValue() { + return this.element.dataset?.formValidationSubmittingIdValue; + } + + // @todo Stimulus >1 + get invalidIdValue() { + return this.element.dataset?.formValidationInvalidIdValue; + } + connect() { this.element.setAttribute("novalidate", true); @@ -19,34 +29,19 @@ export default class extends Controller { submit(event = undefined) { event?.preventDefault(); - event?.stopPropagation(); if (this.element.reportValidity()) { this.element.classList.remove("was-validated"); - this.element.submit(); - this.show(this.submittingTargets); - this.hide(this.invalidTargets); + if (!this.element.hasAttribute("hx-post")) this.element.submit(); + + window.dispatchEvent(new CustomEvent("notification:show", { detail: { id: this.submittingIdValue } })); } else { + event?.stopPropagation(); + this.element.classList.add("was-validated"); - this.hide(this.submittingTargets); - this.show(this.invalidTargets); - } - } - show(elements) { - for (const element of elements) { - element.classList.remove("d-none"); - - setTimeout(() => element.classList.add("show"), 1); - } - } - - hide(elements) { - for (const element of elements) { - element.classList.remove("show"); - - setTimeout(() => element.classList.add("d-none"), 2000); + window.dispatchEvent(new CustomEvent("notification:show", { detail: { id: this.invalidIdValue } })); } } } diff --git a/app/javascript/controllers/notification_controller.js b/app/javascript/controllers/notification_controller.js new file mode 100644 index 00000000..7fbe3b5a --- /dev/null +++ b/app/javascript/controllers/notification_controller.js @@ -0,0 +1,43 @@ +import { Controller } from "stimulus"; + +/* + * Solo se puede mostrar una notificación a la vez + */ +export default class extends Controller { + // @todo Stimulus >1 + get showClasses() { + return (this.element.dataset?.notificationShowClass || "").split(" ").filter(x => x); + } + + // @todo Stimulus >1 + get hideClasses() { + return (this.element.dataset?.notificationHideClass || "").split(" ").filter(x => x); + } + + /* + * Al recibir el evento de mostrar, si no está dirigido al elemento + * actual, se oculta. + */ + show(event = undefined) { + if (event?.detail?.id !== this.element.id) { + this.hide({ detail: { id: this.element.id } }); + return; + } + + this.element.classList.remove("d-none"); + + setTimeout(() => { + this.element.classList.remove(...this.hideClasses); + this.element.classList.add(...this.showClasses); + }, 1); + } + + hide(event = undefined) { + if (event?.detail?.id !== this.element.id) return; + + this.element.classList.remove(...this.showClasses); + this.element.classList.add(...this.hideClasses); + + setTimeout(() => this.element.classList.add("d-none"), 150); + } +} diff --git a/app/views/posts/_form.haml b/app/views/posts/_form.haml index aa8f3d1d..3e09cb72 100644 --- a/app/views/posts/_form.haml +++ b/app/views/posts/_form.haml @@ -31,11 +31,19 @@ end - dir = t("locales.#{@locale}.dir") +- submitting_id = random_id +- invalid_id = random_id +- data = {} +- data[:controller] = 'unsaved-changes form-validation' +- data[:action] = 'unsaved-changes#submit form-validation#submit beforeunload@window->unsaved-changes#unsaved turbolinks:before-visit@window->unsaved-changes#unsavedTurbolinks' +- data[:'unsaved-changes-confirm-value'] = t('.confirm') +- data[:'form-validation-submitting-id-value'] = submitting_id +- data[:'form-validation-invalid-id-value'] = invalid_id -# Comienza el formulario -= form_tag url, method: method, class: "form post #{extra_class}", multipart: true, data: { controller: 'unsaved-changes form-validation', action: 'unsaved-changes#submit form-validation#submit beforeunload@window->unsaved-changes#unsaved turbolinks:before-visit@window->unsaved-changes#unsavedTurbolinks', 'unsaved-changes-confirm-value': t('.confirm') } do += form_tag url, method: method, class: "form post #{extra_class}", multipart: true, data: data do -# Botones de guardado - = render 'posts/submit', site: site, post: post + = render 'posts/submit', site: site, post: post, invalid: invalid_id, submitting: submitting_id = hidden_field_tag 'post[layout]', post.layout.name @@ -43,7 +51,7 @@ = render 'posts/attributes', site: site, post: post, dir: dir, base: 'post', locale: @locale -# Botones de guardado - = render 'posts/submit', site: site, post: post + = render 'posts/submit', site: site, post: post, invalid: invalid_id, submitting: submitting_id -# Formularios usados por los modales = yield(:post_form) diff --git a/app/views/posts/_submit.haml b/app/views/posts/_submit.haml index c3064c53..41d6f420 100644 --- a/app/views/posts/_submit.haml +++ b/app/views/posts/_submit.haml @@ -1,11 +1,3 @@ -- invalid_help = site.config.fetch('invalid_help', t('.invalid_help')) -- submitting_help = site.config.fetch('submitting_help', t('.submitting_help')) - .d-flex.flex-column.flex-md-row.align-items-start.mb-3 - %div - = submit_tag t('.save'), class: 'btn btn-secondary submit-post' - .d-flex.flex-column.position-relative - = render 'bootstrap/alert', class: 'm-0 d-none fade', data: { target: 'form-validation.invalid' } do - = invalid_help - = render 'bootstrap/alert', class: 'm-0 d-none fade position-absolute top-0 left-0', data: { target: 'form-validation.submitting' } do - = submitting_help + %div= submit_tag t('.save'), class: 'btn btn-secondary submit-post' + = render 'posts/validation', site: site, submitting: { id: submitting }, invalid: { id: invalid } diff --git a/app/views/posts/_validation.haml b/app/views/posts/_validation.haml new file mode 100644 index 00000000..c28a743a --- /dev/null +++ b/app/views/posts/_validation.haml @@ -0,0 +1,16 @@ +- invalid = site.config.fetch('invalid', t('.invalid')) +- submitting = site.config.fetch('submitting', t('.submitting')) +- %i[invalid submitting].each do |key| + - local_assigns[key] ||= {} + - local_assigns[key][:data] ||= {} + - local_assigns[key][:data][:target] ||= "form-validation.#{key}" + - local_assigns[key][:data][:action] ||= 'notification:show@window->notification#show' + - local_assigns[key][:data][:controller] ||= 'notification' + - local_assigns[key][:data][:'notification-hide-class'] ||= 'hide' + - local_assigns[key][:data][:'notification-show-class'] ||= 'show' + +.d-flex.flex-column + = render 'bootstrap/alert', class: 'm-0 d-none fade', **local_assigns[:invalid] do + = invalid + = render 'bootstrap/alert', class: 'm-0 d-none fade', **local_assigns[:submitting] do + = submitting diff --git a/config/locales/en.yml b/config/locales/en.yml index 3815f5de..c0ad36d2 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -719,8 +719,9 @@ en: submit: save: 'Save' save_draft: 'Save as draft' - invalid_help: "Some fields need attention! Please search for the fields marked as not valid." - submitting_help: "Saving changes, please wait..." + validation: + invalid: "Some fields need attention! Please search for the fields marked as not valid." + submitting: "Saving changes, please wait..." new_array: remove: "Remove" attributes: diff --git a/config/locales/es.yml b/config/locales/es.yml index 7b981b1d..1fd397e4 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -727,8 +727,9 @@ es: submit: save: 'Guardar' save_draft: 'Guardar como borrador' - invalid_help: "¡Te falta completar algunos campos! Busca los que estén marcados como no válidos." - submitting_help: "Guardando, por favor espera..." + validation: + invalid: "¡Te falta completar algunos campos! Busca los que estén marcados como no válidos." + submitting: "Guardando, por favor espera..." new_array: remove: "Eliminar" attributes: @@ -770,6 +771,8 @@ es: edit: "Editar" new_predefined_array: edit: "Editar" + new_predefined_value: + edit: "Editar" new_array: edit: "Editar" required: "Seleccioná al menos una opción." From 798bb992dc41423b0241510d4614fb39ae7a609f Mon Sep 17 00:00:00 2001 From: f <f@sutty.nl> Date: Wed, 19 Jun 2024 18:20:05 -0300 Subject: [PATCH 4/5] feat: validar formularios htmx --- app/views/posts/_htmx_form.haml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/views/posts/_htmx_form.haml b/app/views/posts/_htmx_form.haml index f4f4a845..7a23445b 100644 --- a/app/views/posts/_htmx_form.haml +++ b/app/views/posts/_htmx_form.haml @@ -27,7 +27,12 @@ multipart: true, class: 'form post ', 'hx-swap': params.require(:swap), - 'hx-target': "##{params.require(:target)}" + 'hx-target': "##{params.require(:target)}", + 'hx-validate': true, + data: { + controller: 'form-validation', + action: 'form-validation#submit' + } } if post.new? From 34aa8822f29254e21bf316f092fe578a665367b0 Mon Sep 17 00:00:00 2001 From: f <f@sutty.nl> Date: Wed, 19 Jun 2024 18:21:44 -0300 Subject: [PATCH 5/5] feat: avisar que se guardaron los cambios --- app/controllers/posts_controller.rb | 8 ++++++-- app/views/posts/_htmx_form.haml | 6 +++++- app/views/posts/attributes/_new_has_one.haml | 8 +++++++- config/locales/en.yml | 2 ++ config/locales/es.yml | 2 ++ 5 files changed, 22 insertions(+), 4 deletions(-) diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index 0f3c24d5..70ba2e54 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -128,7 +128,9 @@ class PostsController < ApplicationController # condiciones. if htmx? if post.persisted? - swap_modals + triggers = { 'notification:show' => { 'id' => params.permit(:saved).values.first } } + + swap_modals(triggers) @value = post.title.value @uuid = post.uuid.value @@ -169,7 +171,9 @@ class PostsController < ApplicationController if htmx? if post.persisted? - swap_modals + triggers = { 'notification:show' => params.permit(:saved).values.first } + + swap_modals(triggers) @value = post.title.value @uuid = post.uuid.value diff --git a/app/views/posts/_htmx_form.haml b/app/views/posts/_htmx_form.haml index 7a23445b..1a8c0597 100644 --- a/app/views/posts/_htmx_form.haml +++ b/app/views/posts/_htmx_form.haml @@ -31,7 +31,9 @@ 'hx-validate': true, data: { controller: 'form-validation', - action: 'form-validation#submit' + action: 'form-validation#submit', + 'form-validation-submitting-id-value': params.permit(:submitting).values.first, + 'form-validation-invalid-id-value': params.permit(:invalid).values.first, } } @@ -78,6 +80,8 @@ %input{ type: 'hidden', name: 'swap', value: params.require(:swap) } - if params[:inverse].present? %input{ type: 'hidden', name: 'inverse', value: params.require(:inverse) } + - if params[:saved].present? + %input{ type: 'hidden', name: 'saved', value: params.require(:saved) } = hidden_field_tag "#{base}[layout]", post.layout.name diff --git a/app/views/posts/attributes/_new_has_one.haml b/app/views/posts/attributes/_new_has_one.haml index 58e098b6..87ef0440 100644 --- a/app/views/posts/attributes/_new_has_one.haml +++ b/app/views/posts/attributes/_new_has_one.haml @@ -19,6 +19,9 @@ post_form_loaded_id = random_id value_list_id = random_id layout = metadata.filter[:layout] + invalid_id = random_id + submitting_id = random_id + saved_id = random_id %div{ data: { controller: 'modal' }} .form-group @@ -43,10 +46,13 @@ = render 'bootstrap/modal', id: id, modal_content_attributes: { class: 'h-100' } do - content_for :"#{id}_body" do -# @todo ocultar el modal después de guardar - .placeholder-glow{ 'hx-get': site_posts_form_path(site, layout: layout, base: id, name: name, form: form_id, swap: 'innerHTML', target: target_id, attribute: 'new_has_one', hide: modal_id, uuid: metadata.value), 'hx-trigger': 'load' } + .placeholder-glow{ 'hx-get': site_posts_form_path(site, layout: layout, base: id, name: name, form: form_id, swap: 'innerHTML', target: target_id, attribute: 'new_has_one', hide: modal_id, uuid: metadata.value, invalid: invalid_id, submitting: submitting_id, saved: saved_id), 'hx-trigger': 'load' } %span.placeholder.w-100.h-100 - content_for :"#{id}_footer" do + = render 'posts/validation', site: site, invalid: { id: invalid_id }, submitting: { id: submitting_id } + = render 'bootstrap/alert', class: 'm-0 d-none fade', id: saved_id, data: { controller: 'notification', action: 'notification:show@window->notification#show', 'notification-hide-class': 'hide', 'notification-show-class': 'show' } do + = t('.saved') = render 'bootstrap/btn', form: form_id, content: t('.save'), type: 'submit', class: 'm-0 mt-1 mr-1' = render 'bootstrap/btn', content: t('.close'), action: 'modal#hide', class: 'm-0 mt-1 mr-1' diff --git a/config/locales/en.yml b/config/locales/en.yml index c0ad36d2..52f002e6 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -965,3 +965,5 @@ en: save: "Save" card: edit: "Edit" + alert: + saved: "Changes were saved!" diff --git a/config/locales/es.yml b/config/locales/es.yml index 1fd397e4..8fe09758 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -975,3 +975,5 @@ es: save: "Guardar" card: edit: "Editar" + alert: + saved: "¡Cambios guardados!"