Files
Thing/src/modules/music/SourcePicker.vue
T
2026-09-12 15:47:16 +08:00

92 lines
3.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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 selectAll = () => emit('update:model-value', [...props.options])
const clearAll = () => emit('update:model-value', [])
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" size="sm" class="h-9 max-w-56 justify-between font-normal">
<span class="truncate">{{ label }}</span>
<ChevronDown class="size-3.5 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent class="w-64 p-2" align="start">
<div class="mb-1 flex items-center justify-between px-1">
<span class="text-[11px] text-muted-foreground">搜索源</span>
<div class="flex items-center gap-2">
<button
type="button"
class="text-[11px] text-muted-foreground hover:text-foreground disabled:opacity-40"
:disabled="modelValue.length === options.length"
@click="selectAll"
>
全选
</button>
<button
type="button"
class="text-[11px] text-muted-foreground hover:text-foreground disabled:opacity-40"
:disabled="modelValue.length === 0"
@click="clearAll"
>
清空
</button>
</div>
</div>
<!-- ScrollArea viewport h-full需要根节点有确定高度才能滚动 -->
<ScrollArea class="h-72">
<div class="space-y-0.5 pr-2">
<label
v-for="code in options"
:key="code"
class="flex cursor-pointer items-center gap-2 rounded-md px-2 py-1.5 hover:bg-accent/60"
>
<Checkbox :model-value="checked.has(code)" @update:model-value="toggle(code)" />
<Label class="cursor-pointer truncate text-[13px]">{{ sourceName(code) }}</Label>
</label>
<p v-if="options.length === 0" class="px-2 py-3 text-[11.5px] text-muted-foreground">
未获取到可用源请先在设置 环境与诊断安装运行时
</p>
</div>
</ScrollArea>
<div class="mt-1 flex items-center justify-between border-t px-1 pt-1.5">
<span class="text-[11px] text-muted-foreground">{{ options.length }} 个可选源</span>
<span class="text-[11px] text-muted-foreground">已选 {{ modelValue.length }}</span>
</div>
</PopoverContent>
</Popover>
</template>