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 }}