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:
parent
8efae0485e
commit
5702f0d198
File diff suppressed because one or more lines are too long
|
@ -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 {
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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 }}
|
||||||
{{ template "select-field" .Tax }}
|
<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 }}
|
||||||
|
</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>
|
||||||
|
|
Loading…
Reference in New Issue