- Create new installation entry form component with validation - Add installation list and add pages with basic routing - Implement custom select component for encounter class selection - Update SelectTrigger styling for better icon positioning
86 lines
2.0 KiB
Vue
86 lines
2.0 KiB
Vue
<script setup lang="ts">
|
|
import { SelectRoot } from 'radix-vue'
|
|
import {
|
|
SelectContent,
|
|
SelectGroup,
|
|
SelectItem,
|
|
SelectLabel,
|
|
SelectSeparator,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from '~/components/pub/ui/select'
|
|
import { cn } from '~/lib/utils'
|
|
|
|
interface Item {
|
|
value: string
|
|
label: string
|
|
code?: string
|
|
}
|
|
|
|
const props = defineProps<{
|
|
modelValue?: string
|
|
items: Item[]
|
|
placeholder?: string
|
|
label?: string
|
|
separator?: boolean
|
|
class?: string
|
|
}>()
|
|
|
|
const emit = defineEmits<{
|
|
'update:modelValue': [value: string]
|
|
}>()
|
|
|
|
// Sort items with selected item first, then alphabetically
|
|
const sortedItems = computed(() => {
|
|
const itemsWithSelection = props.items.map(item => ({
|
|
...item,
|
|
isSelected: item.value === props.modelValue,
|
|
}))
|
|
|
|
return itemsWithSelection.sort((a, b) => {
|
|
// Selected item always comes first
|
|
if (a.isSelected && !b.isSelected) return -1
|
|
if (!a.isSelected && b.isSelected) return 1
|
|
|
|
// If neither or both are selected, sort by label alphabetically
|
|
return a.label.localeCompare(b.label)
|
|
})
|
|
})
|
|
|
|
function onValueChange(value: string) {
|
|
emit('update:modelValue', value)
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<SelectRoot :model-value="modelValue" @update:model-value="onValueChange">
|
|
<SelectTrigger :class="cn('w-full', props.class)">
|
|
<SelectValue :placeholder="placeholder || 'Pilih item'" />
|
|
</SelectTrigger>
|
|
|
|
<SelectContent>
|
|
<SelectGroup>
|
|
<SelectLabel v-if="label">
|
|
{{ label }}
|
|
</SelectLabel>
|
|
|
|
<SelectItem
|
|
v-for="item in sortedItems"
|
|
:key="item.value"
|
|
:value="item.value"
|
|
class="cursor-pointer"
|
|
>
|
|
<div class="flex items-center justify-between w-full">
|
|
<span>{{ item.label }}</span>
|
|
<span v-if="item.code" class="text-xs text-muted-foreground ml-2">
|
|
{{ item.code }}
|
|
</span>
|
|
</div>
|
|
</SelectItem>
|
|
|
|
<SelectSeparator v-if="separator" />
|
|
</SelectGroup>
|
|
</SelectContent>
|
|
</SelectRoot>
|
|
</template>
|