Compare commits

..

3 Commits

Author SHA1 Message Date
jordi fita mas 992bbf32a9 Toggle filters forms
I tried this already when i started adding filters, but i tried to use
AlpineJS for that, and could not because it would reset the context each
time i submitted the filters, due to HTMx replacing the whole content.

I realized that the only thing i need is some “flag” to show and hide
the form with CSS.  I do not even need AlpineJS for that, but i used it
anyway because then i can use the x-cloak thing to hidde the toggle
button for users with JavaScript disabled.

Similarly, the body by default has that “flag” set in the markup, and is
removed when AlpineJS is initialized, thus if JavaScript is disabled the
filters form is shown nevertheless.
2023-05-24 12:13:09 +02:00
jordi fita mas 92edbdfc4d Reindent numerus.css with IntelliJ 2023-05-24 12:06:03 +02:00
jordi fita mas e68eb52578 Don’t show the “(optional)” label for filter inputs
It adds nothing, as all input fields for filters show be optional.
2023-05-24 11:41:48 +02:00
8 changed files with 117 additions and 100 deletions

View File

@ -194,11 +194,11 @@ p, h1, h2, h3, h4, h5, h6 {
} }
input[type="radio"] { input[type="radio"] {
accent-color: var(--numerus--color--black); accent-color: var(--numerus--color--black);
} }
input[type=file] { input[type=file] {
padding: 2rem 1rem 0 1rem; padding: 2rem 1rem 0 1rem;
} }
input[type="submit"], button, .button { input[type="submit"], button, .button {
@ -251,7 +251,7 @@ table {
td { td {
padding: 0 1rem; padding: 0 1rem;
} }
#invoice-list td { #invoice-list td {
@ -374,15 +374,15 @@ input.width-2x {
color: var(--numerus--color--red); color: var(--numerus--color--red);
} }
[lang="en"] textarea:not([required]) + label::after, [lang="en"] form:not(.filters) textarea:not([required]) + label::after,
[lang="en"] input:not([required]) + label::after, [lang="en"] form:not(.filters) input:not([required]) + label::after,
[lang="en"] select:not([required]) + label::after { [lang="en"] form:not(.filters) select:not([required]) + label::after {
content: " (optional)" content: " (optional)"
} }
[lang="ca"] textarea:not([required]) + label::after, [lang="es"] textarea:not([required]) + label::after, [lang="ca"] form:not(.filters) textarea:not([required]) + label::after, [lang="es"] form:not(.filters) textarea:not([required]) + label::after,
[lang="ca"] input:not([required]) + label::after, [lang="es"] input:not([required]) + label::after, [lang="ca"] form:not(.filters) input:not([required]) + label::after, [lang="es"] form:not(.filters) input:not([required]) + label::after,
[lang="ca"] select:not([required]) + label::after, [lang="es"] select:not([required]) + label::after { [lang="ca"] form:not(.filters) select:not([required]) + label::after, [lang="es"] form:not(.filters) select:not([required]) + label::after {
content: " (opcional)" content: " (opcional)"
} }
@ -563,7 +563,7 @@ main > nav {
/* Invoice */ /* Invoice */
.new-invoice-product input { .new-invoice-product input {
width: 100%; width: 100%;
} }
.new-invoice-product { .new-invoice-product {
@ -649,49 +649,49 @@ main > nav {
} }
.invoice-data, .product-data, .expenses-data { .invoice-data, .product-data, .expenses-data {
display: grid; display: grid;
grid-template-columns: repeat(4 , 1fr); grid-template-columns: repeat(4, 1fr);
gap: 1rem; gap: 1rem;
} }
.invoice-data .input:last-child { .invoice-data .input:last-child {
grid-column-start: 1; grid-column-start: 1;
grid-column-end: 5; grid-column-end: 5;
} }
#invoice-summary th { #invoice-summary th {
text-align: left; text-align: left;
padding: 0 0 0 1rem; padding: 0 0 0 1rem;
} }
.button-bar button { .button-bar button {
flex: 1 flex: 1
} }
/* expenses */ /* expenses */
.expenses-data div:last-child { .expenses-data div:last-child {
grid-column-start: 3; grid-column-start: 3;
grid-column-end: 5; grid-column-end: 5;
} }
/* product */ /* product */
.product-data div:last-child { .product-data div:last-child {
grid-column-start: 1; grid-column-start: 1;
grid-column-end: 5; grid-column-end: 5;
} }
/* contact */ /* contact */
.contact-data { .contact-data {
display: grid; display: grid;
gap: 1rem; gap: 1rem;
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(3, 1fr);
} }
/* Multiselect, tags */ /* Multiselect, tags */
.tag { .tag {
padding: 0 0 0 .5rem; padding: 0 0 0 .5rem;
} }
[is="numerus-multiselect"] .tags, [is="numerus-tags"] .tags, [is="numerus-multiselect"] .tags, [is="numerus-tags"] .tags,
@ -724,7 +724,7 @@ main > nav {
} }
[is="numerus-tags"] .tags input, [is="numerus-multiselect"] .tags input { [is="numerus-tags"] .tags input, [is="numerus-multiselect"] .tags input {
height: initial; height: initial;
} }
[is="numerus-multiselect"] .tags:after { [is="numerus-multiselect"] .tags:after {
@ -909,20 +909,28 @@ div[x-data="snackbar"] div[role="alert"].enter.end, div[x-data="snackbar"] div[r
transform: translateY(0); transform: translateY(0);
} }
/* Dashboard */ /* Filters */
.filters { .filters {
display: flex; display: none;
gap: 1rem;
} }
.filters-visible .filters {
display: flex;
gap: 1rem;
}
.filters-visible #filters-toggle {
background-color: var(--numerus--header--background-color);
}
/* Dashboard */
#dashboard-filters { #dashboard-filters {
display: flex; display: flex;
} }
#dashboard-filters fieldset { #dashboard-filters fieldset {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
} }
#dashboard-filters .radio { #dashboard-filters .radio {

View File

@ -712,6 +712,8 @@ htmx.on('closeModal', () => {
}); });
htmx.on(document, 'alpine:init', () => { htmx.on(document, 'alpine:init', () => {
document.body.classList.remove('show-filters');
Alpine.data('snackbar', () => ({ Alpine.data('snackbar', () => ({
show: false, toast: "", toasts: [], timeoutId: null, init() { show: false, toast: "", toasts: [], timeoutId: null, init() {
htmx.on('htmx:error', (error) => { htmx.on('htmx:error', (error) => {

View File

@ -9,7 +9,7 @@
<script type="module" src="/static/numerus.js"></script> <script type="module" src="/static/numerus.js"></script>
<script defer src="/static/alpinejs@3.12.0.min.js"></script> <script defer src="/static/alpinejs@3.12.0.min.js"></script>
</head> </head>
<body> <body class="show-filters">
<header> <header>
<h1><img src="/static/numerus.svg" alt="Numerus" width="261" height="33"></h1> <h1><img src="/static/numerus.svg" alt="Numerus" width="261" height="33"></h1>
<details id="profile-menu" class="menu"> <details id="profile-menu" class="menu">

View File

@ -10,6 +10,7 @@
<a>{{( pgettext "Contacts" "title" )}}</a> <a>{{( pgettext "Contacts" "title" )}}</a>
</p> </p>
<p> <p>
{{ template "filters-toggle" }}
<a class="primary button" <a class="primary button"
href="{{ companyURI "/contacts/new" }}">{{( pgettext "New contact" "action" )}}</a> href="{{ companyURI "/contacts/new" }}">{{( pgettext "New contact" "action" )}}</a>
</p> </p>
@ -18,22 +19,21 @@
{{ define "content" }} {{ define "content" }}
{{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.ContactsIndexPage*/ -}} {{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.ContactsIndexPage*/ -}}
<div aria-label="{{( pgettext "Filters" "title" )}}"> <form class="filters" method="GET" action="{{ companyURI "/contacts"}}"
<form class="filters" method="GET" action="{{ companyURI "/contacts"}}" data-hx-target="main"
data-hx-target="main" data-hx-boost="true"
data-hx-boost="true" data-hx-trigger="change,search,submit"
data-hx-trigger="change,search,submit" aria-labelledby="filters-toggle"
> >
{{ with .Filters }} {{ with .Filters }}
{{ template "input-field" .Name }} {{ template "input-field" .Name }}
{{ template "tags-field" .Tags | addTagsAttr (print `data-conditions="` .TagsCondition.Name `-field"`) }} {{ template "tags-field" .Tags | addTagsAttr (print `data-conditions="` .TagsCondition.Name `-field"`) }}
{{ template "toggle-field" .TagsCondition }} {{ template "toggle-field" .TagsCondition }}
{{ end }} {{ end }}
<noscript> <noscript>
<button type="submit">{{( pgettext "Filter" "action" )}}</button> <button type="submit">{{( pgettext "Filter" "action" )}}</button>
</noscript> </noscript>
</form> </form>
</div>
<table> <table>
<thead> <thead>
<tr> <tr>

View File

@ -11,6 +11,7 @@
<a>{{( pgettext "Expenses" "title" )}}</a> <a>{{( pgettext "Expenses" "title" )}}</a>
</p> </p>
<p> <p>
{{ template "filters-toggle" }}
<a class="primary button" <a class="primary button"
href="{{ companyURI "/expenses/new" }}">{{( pgettext "New expense" "action" )}}</a> href="{{ companyURI "/expenses/new" }}">{{( pgettext "New expense" "action" )}}</a>
</p> </p>
@ -19,23 +20,22 @@
{{ define "content" }} {{ define "content" }}
{{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.expensesIndexPage*/ -}} {{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.expensesIndexPage*/ -}}
<div aria-label="{{( pgettext "Filters" "title" )}}"> <form class="filters" method="GET" action="{{ companyURI "/expenses"}}"
<form class="filters" method="GET" action="{{ companyURI "/expenses"}}" data-hx-target="main" data-hx-boost="true" data-hx-trigger="change,search,submit"
data-hx-target="main" data-hx-boost="true" data-hx-trigger="change,search,submit" aria-labelledby="filters-toggle"
> >
{{ with .Filters }} {{ with .Filters }}
{{ template "select-field" .Customer }} {{ template "select-field" .Customer }}
{{ template "input-field" .FromDate }} {{ template "input-field" .FromDate }}
{{ template "input-field" .ToDate }} {{ template "input-field" .ToDate }}
{{ template "input-field" .InvoiceNumber }} {{ template "input-field" .InvoiceNumber }}
{{ template "tags-field" .Tags | addTagsAttr (print `data-conditions="` .TagsCondition.Name `-field"`) }} {{ template "tags-field" .Tags | addTagsAttr (print `data-conditions="` .TagsCondition.Name `-field"`) }}
{{ template "toggle-field" .TagsCondition }} {{ template "toggle-field" .TagsCondition }}
{{ end }} {{ end }}
<noscript> <noscript>
<button type="submit">{{( pgettext "Filter" "action" )}}</button> <button type="submit">{{( pgettext "Filter" "action" )}}</button>
</noscript> </noscript>
</form> </form>
</div>
<table> <table>
<thead> <thead>
<tr> <tr>

View File

@ -159,3 +159,9 @@
{{ template "select-field" .Tax }} {{ template "select-field" .Tax }}
</fieldset> </fieldset>
{{- end }} {{- end }}
{{ define "filters-toggle" -}}
<button id="filters-toggle" x-cloak x-data="{}"
@click="document.body.classList.toggle('filters-visible')"
type="button">{{(pgettext "Filters" "action")}}</button>
{{- end }}

View File

@ -13,6 +13,7 @@
<form id="batch-form" action="{{ companyURI "/invoices/batch" }}" method="post"> <form id="batch-form" action="{{ companyURI "/invoices/batch" }}" method="post">
{{ csrfToken }} {{ csrfToken }}
<p> <p>
{{ template "filters-toggle" }}
<button type="submit" <button type="submit"
name="action" value="download" name="action" value="download"
>{{( pgettext "Download invoices" "action" )}}</button> >{{( pgettext "Download invoices" "action" )}}</button>
@ -25,23 +26,23 @@
{{ define "content" }} {{ define "content" }}
{{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.InvoicesIndexPage*/ -}} {{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.InvoicesIndexPage*/ -}}
<div aria-label="{{( pgettext "Filters" "title" )}}"> <form class="filters" method="GET" action="{{ companyURI "/invoices"}}"
<form class="filters" method="GET" action="{{ companyURI "/invoices"}}" data-hx-target="main" data-hx-boost="true" data-hx-target="main" data-hx-boost="true" data-hx-trigger="change,search,submit"
data-hx-trigger="change,search,submit"> aria-labelledby="filters-toggle"
{{ with .Filters }} >
{{ template "select-field" .Customer }} {{ with .Filters }}
{{ template "select-field" .InvoiceStatus }} {{ template "select-field" .Customer }}
{{ template "input-field" .FromDate }} {{ template "select-field" .InvoiceStatus }}
{{ template "input-field" .ToDate }} {{ template "input-field" .FromDate }}
{{ template "input-field" .InvoiceNumber }} {{ template "input-field" .ToDate }}
{{ template "tags-field" .Tags | addTagsAttr (print `data-conditions="` .TagsCondition.Name `-field"`) }} {{ template "input-field" .InvoiceNumber }}
{{ template "toggle-field" .TagsCondition }} {{ template "tags-field" .Tags | addTagsAttr (print `data-conditions="` .TagsCondition.Name `-field"`) }}
{{ end }} {{ template "toggle-field" .TagsCondition }}
<noscript> {{ end }}
<button type="submit">{{( pgettext "Filter" "action" )}}</button> <noscript>
</noscript> <button type="submit">{{( pgettext "Filter" "action" )}}</button>
</form> </noscript>
</div> </form>
<table id="invoice-list"> <table id="invoice-list">
<thead> <thead>
<tr> <tr>

View File

@ -10,6 +10,7 @@
<a>{{( pgettext "Products" "title" )}}</a> <a>{{( pgettext "Products" "title" )}}</a>
</p> </p>
<p> <p>
{{ template "filters-toggle" }}
<a class="primary button" <a class="primary button"
href="{{ companyURI "/products/new" }}">{{( pgettext "New product" "action" )}}</a> href="{{ companyURI "/products/new" }}">{{( pgettext "New product" "action" )}}</a>
</p> </p>
@ -18,22 +19,21 @@
{{ define "content" }} {{ define "content" }}
{{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.productsIndexPage*/ -}} {{- /*gotype: dev.tandem.ws/tandem/numerus/pkg.productsIndexPage*/ -}}
<div aria-label="{{( pgettext "Filters" "title" )}}"> <form class="filters" method="GET" action="{{ companyURI "/products"}}"
<form class="filters" method="GET" action="{{ companyURI "/products"}}" data-hx-target="main"
data-hx-target="main" data-hx-boost="true"
data-hx-boost="true" data-hx-trigger="change,search,submit"
data-hx-trigger="change,search,submit" aria-labelledby="filters-toggle"
> >
{{ with .Filters }} {{ with .Filters }}
{{ template "input-field" .Name }} {{ template "input-field" .Name }}
{{ template "tags-field" .Tags | addTagsAttr (print `data-conditions="` .TagsCondition.Name `-field"`) }} {{ template "tags-field" .Tags | addTagsAttr (print `data-conditions="` .TagsCondition.Name `-field"`) }}
{{ template "toggle-field" .TagsCondition }} {{ template "toggle-field" .TagsCondition }}
{{ end }} {{ end }}
<noscript> <noscript>
<button type="submit">{{( pgettext "Filter" "action" )}}</button> <button type="submit">{{( pgettext "Filter" "action" )}}</button>
</noscript> </noscript>
</form> </form>
</div>
<table> <table>
<thead> <thead>
<tr> <tr>