From 149557e42e38ad4e0920309287fcf0b0157370ae Mon Sep 17 00:00:00 2001 From: jordi fita mas Date: Sun, 16 Apr 2023 19:01:11 +0200 Subject: [PATCH] =?UTF-8?q?=E2=80=9CIntegrate=E2=80=9D=20the=20tags?= =?UTF-8?q?=E2=80=99=20condition=20into=20the=20input=20field?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have reconsidered the toggle thing and instead moved the selection into a little menu on top of the input, like the input’s label does à la Material Design. I just moved the checkboxes into a new details, that works as a menu, but i had to add the type="search" to the existing input in the tags field, or the CSS would style the checkboxes as well. I do not do anything when the checkbox selection changes because that already triggers a POST to the server that returns the new HTML with the checkbox changed, and the JavaScript only has to retrieve that new structure, exactly as it does in the initial rendering. Since we want to add a little description to the options, i no longer can use the same SelectOption in ToggleField, even though i could have reused the Group element, but that felt wrong. --- pkg/form.go | 10 +++- pkg/invoices.go | 12 +++-- po/ca.po | 78 ++++++++++++++++-------------- po/es.po | 78 ++++++++++++++++-------------- web/static/numerus.css | 48 +++++++++++++++++- web/static/numerus.js | 35 ++++++++++++++ web/template/form.gohtml | 16 ++++-- web/template/invoices/index.gohtml | 2 +- 8 files changed, 196 insertions(+), 83 deletions(-) diff --git a/pkg/form.go b/pkg/form.go index 7ae4498..1a4dd4d 100644 --- a/pkg/form.go +++ b/pkg/form.go @@ -262,12 +262,18 @@ type ToggleField struct { Name string Label string Selected string - FirstOption *SelectOption - SecondOption *SelectOption + FirstOption *ToggleOption + SecondOption *ToggleOption Attributes []template.HTMLAttr Errors []error } +type ToggleOption struct { + Value string + Label string + Description string +} + func (field *ToggleField) FillValue(r *http.Request) { field.Selected = strings.TrimSpace(r.FormValue(field.Name)) if field.Selected != field.FirstOption.Value && field.Selected != field.SecondOption.Value { diff --git a/pkg/invoices.go b/pkg/invoices.go index 496d4e4..6225607 100644 --- a/pkg/invoices.go +++ b/pkg/invoices.go @@ -190,11 +190,15 @@ func newInvoiceFilterForm(ctx context.Context, conn *Conn, locale *Locale, compa Name: "tags_condition", Label: pgettext("input", "Tags Condition", locale), Selected: "and", - FirstOption: &SelectOption{ - Value: "and", Label: pgettext("tag condition", "All", locale), + FirstOption: &ToggleOption{ + Value: "and", + Label: pgettext("tag condition", "All", locale), + Description: gettext("Invoices must have all the specified labels.", locale), }, - SecondOption: &SelectOption{ - Value: "or", Label: pgettext("tag condition", "Any", locale), + SecondOption: &ToggleOption{ + Value: "or", + Label: pgettext("tag condition", "Any", locale), + Description: gettext("Invoices must have at least one of the specified labels.", locale), }, }, } diff --git a/po/ca.po b/po/ca.po index 021a115..4f09e27 100644 --- a/po/ca.po +++ b/po/ca.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: numerus\n" "Report-Msgid-Bugs-To: jordi@tandem.blog\n" -"POT-Creation-Date: 2023-04-15 20:39+0200\n" +"POT-Creation-Date: 2023-04-16 18:48+0200\n" "PO-Revision-Date: 2023-01-18 17:08+0100\n" "Last-Translator: jordi fita mas \n" "Language-Team: Catalan \n" @@ -456,49 +456,49 @@ msgstr "No podeu deixar la contrasenya en blanc." msgid "Invalid user or password." msgstr "Nom d’usuari o contrasenya incorrectes." -#: pkg/products.go:204 pkg/invoices.go:728 +#: pkg/products.go:204 pkg/invoices.go:732 msgctxt "input" msgid "Name" msgstr "Nom" -#: pkg/products.go:210 pkg/invoices.go:733 +#: pkg/products.go:210 pkg/invoices.go:737 msgctxt "input" msgid "Description" msgstr "Descripció" -#: pkg/products.go:215 pkg/invoices.go:737 +#: pkg/products.go:215 pkg/invoices.go:741 msgctxt "input" msgid "Price" msgstr "Preu" -#: pkg/products.go:225 pkg/invoices.go:763 +#: pkg/products.go:225 pkg/invoices.go:767 msgctxt "input" msgid "Taxes" msgstr "Imposts" -#: pkg/products.go:231 pkg/invoices.go:187 pkg/invoices.go:578 -#: pkg/invoices.go:960 pkg/contacts.go:267 +#: pkg/products.go:231 pkg/invoices.go:187 pkg/invoices.go:582 +#: pkg/invoices.go:964 pkg/contacts.go:267 msgctxt "input" msgid "Tags" msgstr "Etiquetes" -#: pkg/products.go:250 pkg/profile.go:92 pkg/invoices.go:802 +#: pkg/products.go:250 pkg/profile.go:92 pkg/invoices.go:806 msgid "Name can not be empty." msgstr "No podeu deixar el nom en blanc." -#: pkg/products.go:251 pkg/invoices.go:803 +#: pkg/products.go:251 pkg/invoices.go:807 msgid "Price can not be empty." msgstr "No podeu deixar el preu en blanc." -#: pkg/products.go:252 pkg/invoices.go:804 +#: pkg/products.go:252 pkg/invoices.go:808 msgid "Price must be a number greater than zero." msgstr "El preu ha de ser un número major a zero." -#: pkg/products.go:254 pkg/invoices.go:812 +#: pkg/products.go:254 pkg/invoices.go:816 msgid "Selected tax is not valid." msgstr "Heu seleccionat un impost que no és vàlid." -#: pkg/products.go:255 pkg/invoices.go:813 +#: pkg/products.go:255 pkg/invoices.go:817 msgid "You can only select a tax of each class." msgstr "Només podeu seleccionar un impost de cada classe." @@ -606,7 +606,7 @@ msgstr "La confirmació no és igual a la contrasenya." msgid "Selected language is not valid." msgstr "Heu seleccionat un idioma que no és vàlid." -#: pkg/invoices.go:160 pkg/invoices.go:561 +#: pkg/invoices.go:160 pkg/invoices.go:565 msgctxt "input" msgid "Customer" msgstr "Client" @@ -615,7 +615,7 @@ msgstr "Client" msgid "All customers" msgstr "Tots els clients" -#: pkg/invoices.go:166 pkg/invoices.go:555 +#: pkg/invoices.go:166 pkg/invoices.go:559 msgctxt "input" msgid "Invoice Status" msgstr "Estat de la factura" @@ -644,95 +644,103 @@ msgctxt "input" msgid "Tags Condition" msgstr "Condició de les etiquetes" -#: pkg/invoices.go:194 +#: pkg/invoices.go:195 msgctxt "tag condition" msgid "All" msgstr "Totes" -#: pkg/invoices.go:197 +#: pkg/invoices.go:196 +msgid "Invoices must have all the specified labels." +msgstr "Les factures han de tenir totes les etiquetes." + +#: pkg/invoices.go:200 msgctxt "tag condition" msgid "Any" msgstr "Qualsevol" -#: pkg/invoices.go:401 +#: pkg/invoices.go:201 +msgid "Invoices must have at least one of the specified labels." +msgstr "Les factures han de tenir com a mínim una de les etiquetes." + +#: pkg/invoices.go:405 msgid "Select a customer to bill." msgstr "Escolliu un client a facturar." -#: pkg/invoices.go:500 +#: pkg/invoices.go:504 msgid "invoices.zip" msgstr "factures.zip" -#: pkg/invoices.go:506 pkg/invoices.go:946 +#: pkg/invoices.go:510 pkg/invoices.go:950 msgid "Invalid action" msgstr "Acció invàlida." -#: pkg/invoices.go:567 +#: pkg/invoices.go:571 msgctxt "input" msgid "Invoice Date" msgstr "Data de factura" -#: pkg/invoices.go:573 +#: pkg/invoices.go:577 msgctxt "input" msgid "Notes" msgstr "Notes" -#: pkg/invoices.go:583 +#: pkg/invoices.go:587 msgctxt "input" msgid "Payment Method" msgstr "Mètode de pagament" -#: pkg/invoices.go:620 +#: pkg/invoices.go:624 msgid "Selected invoice status is not valid." msgstr "Heu seleccionat un estat de factura que no és vàlid." -#: pkg/invoices.go:621 +#: pkg/invoices.go:625 msgid "Selected customer is not valid." msgstr "Heu seleccionat un client que no és vàlid." -#: pkg/invoices.go:622 +#: pkg/invoices.go:626 msgid "Invoice date can not be empty." msgstr "No podeu deixar la data de la factura en blanc." -#: pkg/invoices.go:623 +#: pkg/invoices.go:627 msgid "Invoice date must be a valid date." msgstr "La data de facturació ha de ser vàlida." -#: pkg/invoices.go:625 +#: pkg/invoices.go:629 msgid "Selected payment method is not valid." msgstr "Heu seleccionat un mètode de pagament que no és vàlid." -#: pkg/invoices.go:718 pkg/invoices.go:723 +#: pkg/invoices.go:722 pkg/invoices.go:727 msgctxt "input" msgid "Id" msgstr "Identificador" -#: pkg/invoices.go:746 +#: pkg/invoices.go:750 msgctxt "input" msgid "Quantity" msgstr "Quantitat" -#: pkg/invoices.go:754 +#: pkg/invoices.go:758 msgctxt "input" msgid "Discount (%)" msgstr "Descompte (%)" -#: pkg/invoices.go:801 +#: pkg/invoices.go:805 msgid "Product ID can not be empty." msgstr "No podeu deixar l’identificador del producte en blanc." -#: pkg/invoices.go:806 +#: pkg/invoices.go:810 msgid "Quantity can not be empty." msgstr "No podeu deixar la quantitat en blanc." -#: pkg/invoices.go:807 +#: pkg/invoices.go:811 msgid "Quantity must be a number greater than zero." msgstr "La quantitat ha de ser un número major a zero." -#: pkg/invoices.go:809 +#: pkg/invoices.go:813 msgid "Discount can not be empty." msgstr "No podeu deixar el descompte en blanc." -#: pkg/invoices.go:810 +#: pkg/invoices.go:814 msgid "Discount must be a percentage between 0 and 100." msgstr "El descompte ha de ser un percentatge entre 0 i 100." diff --git a/po/es.po b/po/es.po index a14f215..a402cf0 100644 --- a/po/es.po +++ b/po/es.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: numerus\n" "Report-Msgid-Bugs-To: jordi@tandem.blog\n" -"POT-Creation-Date: 2023-04-15 20:39+0200\n" +"POT-Creation-Date: 2023-04-16 18:48+0200\n" "PO-Revision-Date: 2023-01-18 17:45+0100\n" "Last-Translator: jordi fita mas \n" "Language-Team: Spanish \n" @@ -456,49 +456,49 @@ msgstr "No podéis dejar la contraseña en blanco." msgid "Invalid user or password." msgstr "Nombre de usuario o contraseña inválido." -#: pkg/products.go:204 pkg/invoices.go:728 +#: pkg/products.go:204 pkg/invoices.go:732 msgctxt "input" msgid "Name" msgstr "Nombre" -#: pkg/products.go:210 pkg/invoices.go:733 +#: pkg/products.go:210 pkg/invoices.go:737 msgctxt "input" msgid "Description" msgstr "Descripción" -#: pkg/products.go:215 pkg/invoices.go:737 +#: pkg/products.go:215 pkg/invoices.go:741 msgctxt "input" msgid "Price" msgstr "Precio" -#: pkg/products.go:225 pkg/invoices.go:763 +#: pkg/products.go:225 pkg/invoices.go:767 msgctxt "input" msgid "Taxes" msgstr "Impuestos" -#: pkg/products.go:231 pkg/invoices.go:187 pkg/invoices.go:578 -#: pkg/invoices.go:960 pkg/contacts.go:267 +#: pkg/products.go:231 pkg/invoices.go:187 pkg/invoices.go:582 +#: pkg/invoices.go:964 pkg/contacts.go:267 msgctxt "input" msgid "Tags" msgstr "Etiquetes" -#: pkg/products.go:250 pkg/profile.go:92 pkg/invoices.go:802 +#: pkg/products.go:250 pkg/profile.go:92 pkg/invoices.go:806 msgid "Name can not be empty." msgstr "No podéis dejar el nombre en blanco." -#: pkg/products.go:251 pkg/invoices.go:803 +#: pkg/products.go:251 pkg/invoices.go:807 msgid "Price can not be empty." msgstr "No podéis dejar el precio en blanco." -#: pkg/products.go:252 pkg/invoices.go:804 +#: pkg/products.go:252 pkg/invoices.go:808 msgid "Price must be a number greater than zero." msgstr "El precio tiene que ser un número mayor a cero." -#: pkg/products.go:254 pkg/invoices.go:812 +#: pkg/products.go:254 pkg/invoices.go:816 msgid "Selected tax is not valid." msgstr "Habéis escogido un impuesto que no es válido." -#: pkg/products.go:255 pkg/invoices.go:813 +#: pkg/products.go:255 pkg/invoices.go:817 msgid "You can only select a tax of each class." msgstr "Solo podéis escoger un impuesto de cada clase." @@ -606,7 +606,7 @@ msgstr "La confirmación no corresponde con la contraseña." msgid "Selected language is not valid." msgstr "Habéis escogido un idioma que no es válido." -#: pkg/invoices.go:160 pkg/invoices.go:561 +#: pkg/invoices.go:160 pkg/invoices.go:565 msgctxt "input" msgid "Customer" msgstr "Cliente" @@ -615,7 +615,7 @@ msgstr "Cliente" msgid "All customers" msgstr "Todos los clientes" -#: pkg/invoices.go:166 pkg/invoices.go:555 +#: pkg/invoices.go:166 pkg/invoices.go:559 msgctxt "input" msgid "Invoice Status" msgstr "Estado de la factura" @@ -644,95 +644,103 @@ msgctxt "input" msgid "Tags Condition" msgstr "Condición de las etiquetas" -#: pkg/invoices.go:194 +#: pkg/invoices.go:195 msgctxt "tag condition" msgid "All" msgstr "Todas" -#: pkg/invoices.go:197 +#: pkg/invoices.go:196 +msgid "Invoices must have all the specified labels." +msgstr "Las facturas deben tener todas las etiquetas." + +#: pkg/invoices.go:200 msgctxt "tag condition" msgid "Any" msgstr "Cualquiera" -#: pkg/invoices.go:401 +#: pkg/invoices.go:201 +msgid "Invoices must have at least one of the specified labels." +msgstr "Las facturas debent tener como mínimo una de las etiquetas." + +#: pkg/invoices.go:405 msgid "Select a customer to bill." msgstr "Escoged un cliente a facturar." -#: pkg/invoices.go:500 +#: pkg/invoices.go:504 msgid "invoices.zip" msgstr "facturas.zip" -#: pkg/invoices.go:506 pkg/invoices.go:946 +#: pkg/invoices.go:510 pkg/invoices.go:950 msgid "Invalid action" msgstr "Acción inválida." -#: pkg/invoices.go:567 +#: pkg/invoices.go:571 msgctxt "input" msgid "Invoice Date" msgstr "Fecha de factura" -#: pkg/invoices.go:573 +#: pkg/invoices.go:577 msgctxt "input" msgid "Notes" msgstr "Notas" -#: pkg/invoices.go:583 +#: pkg/invoices.go:587 msgctxt "input" msgid "Payment Method" msgstr "Método de pago" -#: pkg/invoices.go:620 +#: pkg/invoices.go:624 msgid "Selected invoice status is not valid." msgstr "Habéis escogido un estado de factura que no es válido." -#: pkg/invoices.go:621 +#: pkg/invoices.go:625 msgid "Selected customer is not valid." msgstr "Habéis escogido un cliente que no es válido." -#: pkg/invoices.go:622 +#: pkg/invoices.go:626 msgid "Invoice date can not be empty." msgstr "No podéis dejar la fecha de la factura en blanco." -#: pkg/invoices.go:623 +#: pkg/invoices.go:627 msgid "Invoice date must be a valid date." msgstr "La fecha de factura debe ser válida." -#: pkg/invoices.go:625 +#: pkg/invoices.go:629 msgid "Selected payment method is not valid." msgstr "Habéis escogido un método de pago que no es válido." -#: pkg/invoices.go:718 pkg/invoices.go:723 +#: pkg/invoices.go:722 pkg/invoices.go:727 msgctxt "input" msgid "Id" msgstr "Identificador" -#: pkg/invoices.go:746 +#: pkg/invoices.go:750 msgctxt "input" msgid "Quantity" msgstr "Cantidad" -#: pkg/invoices.go:754 +#: pkg/invoices.go:758 msgctxt "input" msgid "Discount (%)" msgstr "Descuento (%)" -#: pkg/invoices.go:801 +#: pkg/invoices.go:805 msgid "Product ID can not be empty." msgstr "No podéis dejar el identificador de producto en blanco." -#: pkg/invoices.go:806 +#: pkg/invoices.go:810 msgid "Quantity can not be empty." msgstr "No podéis dejar la cantidad en blanco." -#: pkg/invoices.go:807 +#: pkg/invoices.go:811 msgid "Quantity must be a number greater than zero." msgstr "La cantidad tiene que ser un número mayor a cero." -#: pkg/invoices.go:809 +#: pkg/invoices.go:813 msgid "Discount can not be empty." msgstr "No podéis dejar el descuento en blanco." -#: pkg/invoices.go:810 +#: pkg/invoices.go:814 msgid "Discount must be a percentage between 0 and 100." msgstr "El descuento tiene que ser un porcentaje entre 0 y 100." diff --git a/web/static/numerus.css b/web/static/numerus.css index aaa5bad..308856e 100644 --- a/web/static/numerus.css +++ b/web/static/numerus.css @@ -669,7 +669,7 @@ main > nav { background: rgba(255, 255, 255, .4); } -[is="numerus-multiselect"] .tags input, [is="numerus-tags"] .tags input { +[is="numerus-multiselect"] .tags input, [is="numerus-tags"] .tags input[type="search"] { flex: 1; width: 100%; border: 0; @@ -678,6 +678,8 @@ main > nav { overflow: hidden; text-overflow: ellipsis; appearance: none; + padding: 0; + min-width: initial; } [is="numerus-multiselect"] .options { @@ -700,6 +702,50 @@ main > nav { background-color: var(--numerus--color--light-gray); } +[is="numerus-tags"] details { + background-color: var(--numerus--background-color); + position: absolute; + right: 2rem; + top: -.9rem; + font-size: 0.8em; + padding: 0 0.5em; +} + +[is="numerus-tags"] details summary { + display: revert; +} + +[is="numerus-tags"] [role="menu"] { + min-width: 27em; +} + +[is="numerus-tags"] [role="menu"] li { + display: inline-flex; + flex-direction: column; + justify-content: center; + font-size: 1.6rem; + padding: 0.25em 0.5em; +} + +[is="numerus-tags"] [role="menu"] li + li { + margin-top: 0.75em; +} + +[is="numerus-tags"] [role="menu"] label { + color: var(--numerus--text-color); + font-size: 1em; + background-color: inherit; + position: initial; + pointer-events: initial; + cursor: pointer; + gap: 0.5em; +} + +[is="numerus-tags"] [role="menu"] label[title]::after { + content: attr(title); + display: block; +} + /* Modal */ dialog { margin: auto; diff --git a/web/static/numerus.js b/web/static/numerus.js index 4bf11e9..1c7e3e2 100644 --- a/web/static/numerus.js +++ b/web/static/numerus.js @@ -389,12 +389,47 @@ class Tags extends HTMLDivElement { this.tagList.append(this.search); this.search.id = this.input.id; this.input.removeAttribute('id'); + this.search.setAttribute('type', 'search'); this.input.setAttribute('aria-hidden', 'true'); this.search.setAttribute('spellcheck', 'false'); this.search.setAttribute('autocomplete', 'false'); // Must come after the search input this.tagList.append(this.label); + + const conditionsId = this.input.dataset.conditions; + if (conditionsId !== "") { + const conditions = document.getElementById(conditionsId); + if (conditions) { + const details = document.createElement('details'); + details.classList.add('menu'); + this.tagList.append(details); + + const summary = document.createElement('summary'); + details.append(summary); + + const ul = document.createElement('ul'); + ul.setAttribute('role', 'menu'); + details.append(ul); + + const options = conditions.querySelectorAll('label'); + if (options && options.length > 0) { + summary.textContent = options[0].textContent.trim(); + } + for (const option of options) { + const li = document.createElement('li'); + li.setAttribute('role', 'presentation'); + li.append(option); + ul.append(li); + + const checkbox = option.querySelector('input'); + if (checkbox && checkbox.checked) { + summary.textContent = option.textContent.trim(); + } + } + conditions.remove(); + } + } } removeTags() { diff --git a/web/template/form.gohtml b/web/template/form.gohtml index 9ca8916..5204f65 100644 --- a/web/template/form.gohtml +++ b/web/template/form.gohtml @@ -95,11 +95,17 @@ {{ define "toggle-field" -}} {{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.ToggleField*/ -}} -
+
{{ .Label }} - - + +
{{- end }} diff --git a/web/template/invoices/index.gohtml b/web/template/invoices/index.gohtml index f20fe76..29f4947 100644 --- a/web/template/invoices/index.gohtml +++ b/web/template/invoices/index.gohtml @@ -35,7 +35,7 @@ {{ template "input-field" .FromDate }} {{ template "input-field" .ToDate }} {{ template "input-field" .InvoiceNumber }} - {{ template "tags-field" .Tags }} + {{ template "tags-field" .Tags | addTagsAttr (print `data-conditions="` .TagsCondition.Name `-field"`) }} {{ template "toggle-field" .TagsCondition }} {{ end }}