console/frontend: turn time range and dimensions into comboboxes

This commit is contained in:
Vincent Bernat
2022-06-18 20:30:38 +02:00
parent dfd9d32475
commit 418c9c53d5
4 changed files with 78 additions and 23 deletions

View File

@@ -4,11 +4,11 @@
<slot
:id="id"
:child-class="{
'peer block w-full appearance-none rounded-t-lg border-0 border-b-2 bg-white px-2.5 py-1.5 text-sm text-gray-900 focus:outline-none focus:ring-0 dark:bg-gray-900 dark:text-white': true,
'peer block w-full appearance-none rounded-t-lg border-0 border-b-2 bg-white px-2.5 py-1.5 text-sm text-gray-900 focus-withinoutline-none focus-withinring-0 dark:bg-gray-900 dark:text-white': true,
'pt-4': label,
'dark:focus:border-red-500 dark:focus-within:border-red-500 border-red-600 focus:border-red-600 focus-withing:border-red-600':
'dark:focus-withinborder-red-500 dark:focus-within:border-red-500 border-red-600 focus-withinborder-red-600 focus-withing:border-red-600':
error,
'border-gray-300 focus:border-blue-600 focus-within:border-blue-600 dark:border-gray-600 dark:focus:border-blue-500 dark:focus-within:border-blue-500':
'border-gray-300 focus-withinborder-blue-600 focus-within:border-blue-600 dark:border-gray-600 dark:focus-withinborder-blue-500 dark:focus-within:border-blue-500':
!error,
}"
/>
@@ -17,10 +17,10 @@
:for="id"
:class="{
'text-red-600 dark:text-red-500': error,
'text-gray-500 peer-focus:text-blue-600 dark:text-gray-400 dark:peer-focus:text-blue-500':
'peer-focus-withintext-blue-600 dark:peer-focus-withintext-blue-500 text-gray-500 dark:text-gray-400':
!error,
}"
class="z-5 absolute top-3 left-2.5 origin-[0] -translate-y-3 scale-75 transform font-sans text-sm duration-300 peer-placeholder-shown:translate-y-0 peer-placeholder-shown:scale-100 peer-focus:-translate-y-3 peer-focus:scale-75"
class="z-5 peer-focus-within-translate-y-3 peer-focus-withinscale-75 absolute top-3 left-2.5 origin-[0] -translate-y-3 scale-75 transform font-sans text-sm duration-300 peer-placeholder-shown:translate-y-0 peer-placeholder-shown:scale-100"
>{{ label }}</label
>
</div>

View File

@@ -6,6 +6,7 @@
:error="dimensionsError"
multiple
label="Dimensions"
filter="name"
class="col-span-2 lg:col-span-1"
>
<template #selected>

View File

@@ -1,5 +1,6 @@
<template>
<Listbox
<component
:is="component.Box"
:class="$attrs['class']"
:multiple="multiple"
:model-value="modelValue"
@@ -7,16 +8,29 @@
>
<div class="relative">
<InputBase v-slot="{ id, childClass }" v-bind="otherAttrs" :error="error">
<ListboxButton :id="id" :class="childClass">
<span class="block truncate pr-10 text-left">
<slot name="selected"></slot>
</span>
<span
class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2"
<component :is="component.Widget" :id="id" :class="childClass">
<div class="flex flex-wrap items-center gap-x-2 pr-10 text-left">
<span>
<slot name="selected"></slot>
</span>
<component
:is="component.Input"
class="w-16 grow border-none p-0 focus:outline-none"
placeholder="Search..."
@change="query = $event.target.value"
@focus="query = ''"
>
</component>
</div>
<component
:is="component.Button"
:id="id"
class="absolute inset-y-0 right-0 flex items-center pr-2"
:class="{ 'pointer-events-none': !component.Input }"
>
<SelectorIcon class="h-5 w-5 text-gray-400" aria-hidden="true" />
</span>
</ListboxButton>
</component>
</component>
</InputBase>
<transition
@@ -27,11 +41,13 @@
leave-from-class="transform scale-100 opacity-100"
leave-to-class="transform scale-95 opacity-0"
>
<ListboxOptions
<component
:is="component.Options"
class="absolute z-50 max-h-60 w-full overflow-auto rounded bg-white py-1 text-sm text-gray-700 shadow dark:bg-gray-900 dark:text-gray-200 dark:shadow-white/10"
>
<ListboxOption
v-for="item in items"
<component
:is="component.Option"
v-for="item in filteredItems"
v-slot="{ selected, active }"
:key="item.id"
:value="item"
@@ -54,11 +70,11 @@
<CheckIcon class="h-5 w-5" aria-hidden="true" />
</span>
</li>
</ListboxOption>
</ListboxOptions>
</component>
</component>
</transition>
</div>
</Listbox>
</component>
</template>
<script>
@@ -68,7 +84,7 @@ export default {
</script>
<script setup>
defineProps({
const props = defineProps({
modelValue: {
type: Object,
required: true,
@@ -78,28 +94,65 @@ defineProps({
default: "",
},
items: {
// Each item in the array is expected to have "id" and "name".
// Each item in the array is expected to have "id".
type: Array,
required: true,
},
multiple: {
// Allow to select multiple values.
type: Boolean,
default: false,
},
filter: {
// Enable filtering on the provided property.
type: String,
default: null,
},
});
defineEmits(["update:modelValue"]);
import { computed, useAttrs } from "vue";
import { ref, computed, useAttrs } from "vue";
import {
Listbox,
Combobox,
ListboxButton,
ComboboxButton,
ListboxOptions,
ComboboxOptions,
ListboxOption,
ComboboxOption,
ComboboxInput,
} from "@headlessui/vue";
import { CheckIcon, SelectorIcon } from "@heroicons/vue/solid";
import InputBase from "@/components/InputBase.vue";
const attrs = useAttrs();
const query = ref("");
const component = computed(() =>
props.filter === null
? {
Box: Listbox,
Widget: ListboxButton,
Button: "span",
Options: ListboxOptions,
Option: ListboxOption,
}
: {
Box: Combobox,
Widget: "div",
Button: ComboboxButton,
Options: ComboboxOptions,
Option: ComboboxOption,
Input: ComboboxInput,
}
);
const filteredItems = computed(() =>
props.filter === null
? props.items
: props.items.filter((it) =>
it[props.filter].toLowerCase().includes(query.value.toLowerCase())
)
);
const otherAttrs = computed(() => {
// eslint-disable-next-line no-unused-vars
const { class: _, ...others } = attrs;

View File

@@ -3,6 +3,7 @@
<InputListBox
v-model="selectedPreset"
:items="presets"
filter="name"
label="Presets"
class="col-span-2 sm:col-span-1"
>