Start “improving” the user interface with AlpineJS: tax selector

It is a shitty component, but i do not have more time today to do it
better.
This commit is contained in:
jordi fita mas 2023-03-14 18:07:38 +01:00
parent 8efae0485e
commit 5702f0d198
4 changed files with 161 additions and 1 deletions

5
web/static/alpinejs@3.12.0.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -588,6 +588,102 @@ main > nav {
right: 0; right: 0;
} }
/* AlpineJS */
[x-cloak] {
display: none !important;
}
/* Multiselect */
.multiselect {
max-width: 35rem;
}
.multiselect .tags, .multiselect .options {
font-size: 1em;
list-style: none;
color: var(--numerus--text-color);
background-color: var(--numerus--background-color);
border: 1px solid var(--numerus--color--black);
border-radius: 0;
}
.multiselect .tags {
display: flex;
flex-wrap: wrap;
gap: 1rem;
padding: 1rem 4rem 1rem 2rem;
position: relative;
cursor: pointer;
min-height: calc(1.5em + 2rem);
min-width: 20rem;
}
.multiselect ul + .placeholder {
position: absolute;
font-style: italic;
pointer-events: none;
font-size: 1em;
background-color: initial;
top: 1rem;
left: 2rem;
transition: 0.2s;
}
.multiselect ul:not(.empty) + .placeholder {
background-color: var(--numerus--background-color);
top: -.9rem;
left: 2rem;
font-size: 0.8em;
padding: 0 .25rem;
}
.multiselect ul + .placeholder::after {
content: " (optional)";
}
.multiselect .tags:after {
content: '';
border-top: 6px solid black;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
right: 1.4rem;
position: absolute;
top: 50%;
transform: translateY(-50%);
cursor: pointer;
}
.multiselect .tags li {
background-color: var(--numerus--color--hay);
}
.multiselect .tags button {
border: none;
cursor: pointer;
background: transparent;
min-width: initial;
}
.multiselect .tags button:hover {
background: rgba(255, 255, 255, .4);
}
.multiselect .options {
padding: 0;
border-top: 0;
}
.multiselect .options li {
display: block;
width: 100%;
cursor: pointer;
padding: 1rem 2rem;
}
.multiselect .options li:hover {
background-color: var(--numerus--color--light-gray);
}
/* Remix Icon */ /* Remix Icon */
@font-face { @font-face {

View File

@ -5,6 +5,14 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ template "title" . }} — Numerus</title> <title>{{ template "title" . }} — Numerus</title>
<link rel="stylesheet" type="text/css" media="screen" href="/static/numerus.css"> <link rel="stylesheet" type="text/css" media="screen" href="/static/numerus.css">
<script defer src="/static/alpinejs@3.12.0.min.js"></script>
<noscript>
<style>
[x-cloak] {
display: revert !important;
}
</style>
</noscript>
</head> </head>
<body> <body>
<header> <header>

View File

@ -20,7 +20,58 @@
{{ template "input-field" .Name | addInputAttr "autofocus" }} {{ template "input-field" .Name | addInputAttr "autofocus" }}
{{ template "input-field" .Description }} {{ template "input-field" .Description }}
{{ template "input-field" .Price }} {{ template "input-field" .Price }}
<div x-data="{
options: [],
open: false,
init() {
const wrap = $el.querySelector('.input');
const select = wrap.querySelector('select');
for (const option of select.options) {
this.options.push({
value: option.value,
label: option.innerText,
selected: option.getAttribute('selected') !== null,
});
}
wrap.remove();
}
}">
<div x-cloak>
{{ template "select-field" .Tax }} {{ template "select-field" .Tax }}
</div>
{{ with .Tax }}
<template x-if="true">
<div class="input multiselect {{ if .Errors }}has-errors{{ end }}">
<ul class="tags" :class="{'empty': options.filter(option => option.selected).length === 0}"
@click="open = !open" @click.away="open = false">
<template x-for="(option) in options.filter(option => option.selected)">
<li>
<input type="hidden" name="{{ .Name }}" :value="option.value">
<span x-text="option.label"></span>
<button type="button" @click.stop="option.selected = false">×</button>
</li>
</template>
</ul>
<span class="placeholder">{{ .Label }}</span>
<ul class="options" x-show.transition="open">
<template x-for="(option) in options.filter(option => !option.selected)">
<li
x-text="option.label"
@click.stop="option.selected = true"
></li>
</template>
</ul>
{{- if .Errors }}
<ul>
{{- range $error := .Errors }}
<li>{{ . }}</li>
{{- end }}
</ul>
{{- end }}
</div>
</template>
{{ end }}
</div>
<fieldset> <fieldset>
<button class="primary" type="submit">{{( pgettext "Update product" "action" )}}</button> <button class="primary" type="submit">{{( pgettext "Update product" "action" )}}</button>