mirror of
https://github.com/akvorado/akvorado.git
synced 2025-12-11 22:14:02 +01:00
console/frontend: turn time range and dimensions into comboboxes
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
:error="dimensionsError"
|
||||
multiple
|
||||
label="Dimensions"
|
||||
filter="name"
|
||||
class="col-span-2 lg:col-span-1"
|
||||
>
|
||||
<template #selected>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
<InputListBox
|
||||
v-model="selectedPreset"
|
||||
:items="presets"
|
||||
filter="name"
|
||||
label="Presets"
|
||||
class="col-span-2 sm:col-span-1"
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user