71 lines
2.5 KiB
Vue
71 lines
2.5 KiB
Vue
<script setup lang="ts">
|
||
import { computed, ref } from 'vue'
|
||
import { ChevronDown } from '@lucide/vue'
|
||
import { Button } from '@/components/ui/button'
|
||
import { Checkbox } from '@/components/ui/checkbox'
|
||
import { Label } from '@/components/ui/label'
|
||
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
|
||
import { ScrollArea } from '@/components/ui/scroll-area'
|
||
import { sourceName } from './sources'
|
||
|
||
const props = defineProps<{
|
||
modelValue: string[]
|
||
/** 可选源(客户端名)列表 */
|
||
options: string[]
|
||
}>()
|
||
const emit = defineEmits<{ 'update:model-value': [string[]] }>()
|
||
|
||
const open = ref(false)
|
||
|
||
const checked = computed(() => new Set(props.modelValue))
|
||
|
||
const toggle = (code: string) => {
|
||
const next = new Set(checked.value)
|
||
if (next.has(code)) next.delete(code)
|
||
else next.add(code)
|
||
emit('update:model-value', [...next])
|
||
}
|
||
|
||
const label = computed(() => {
|
||
if (props.modelValue.length === 0) return '未选择'
|
||
if (props.modelValue.length === 1) return sourceName(props.modelValue[0])
|
||
return `已选 ${props.modelValue.length} 个源`
|
||
})
|
||
</script>
|
||
|
||
<template>
|
||
<Popover v-model:open="open">
|
||
<PopoverTrigger as-child>
|
||
<Button variant="outline" class="justify-between font-normal" size="sm">
|
||
<span class="truncate">{{ label }}</span>
|
||
<ChevronDown class="size-3.5 opacity-50 shrink-0" />
|
||
</Button>
|
||
</PopoverTrigger>
|
||
<PopoverContent class="w-64 p-2" align="start">
|
||
<!-- ScrollArea 的 viewport h-full 需要 root 有确定高度才滚动;max-h 不生效,用固定 h-72 -->
|
||
<ScrollArea class="h-72">
|
||
<div class="space-y-0.5 pr-2">
|
||
<label
|
||
v-for="code in options"
|
||
:key="code"
|
||
class="flex items-center gap-2 rounded-md px-2 py-1.5 cursor-pointer hover:bg-muted/50"
|
||
>
|
||
<Checkbox
|
||
:model-value="checked.has(code)"
|
||
@update:model-value="toggle(code)"
|
||
/>
|
||
<Label class="text-sm cursor-pointer truncate">{{ sourceName(code) }}</Label>
|
||
</label>
|
||
<p v-if="options.length === 0" class="px-2 py-3 text-xs text-muted-foreground">
|
||
未获取到可用源,请先安装环境
|
||
</p>
|
||
</div>
|
||
</ScrollArea>
|
||
<div class="mt-1 border-t pt-1.5 px-1 flex items-center justify-between">
|
||
<span class="text-xs text-muted-foreground">{{ options.length }} 个可选源</span>
|
||
<span class="text-xs text-muted-foreground">已选 {{ props.modelValue.length }}</span>
|
||
</div>
|
||
</PopoverContent>
|
||
</Popover>
|
||
</template>
|