-
-
Notifications
You must be signed in to change notification settings - Fork 80
Expand file tree
/
Copy pathSearchPanel.vue
More file actions
130 lines (121 loc) · 3.39 KB
/
SearchPanel.vue
File metadata and controls
130 lines (121 loc) · 3.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
<script setup lang="ts">
import type { FilterMatchRule } from '~/utils/icon'
import { useVModel } from '@vueuse/core'
interface ModelValue { search?: string | false, selected?: string[] | null }
const props = withDefaults(
defineProps<{
rules: FilterMatchRule[]
modelValue?: ModelValue
selectedContainerClass?: string
}>(),
{
modelValue: () => ({
search: '',
selected: null,
}),
selectedContainerClass: '',
},
)
const emit = defineEmits<{
(e: 'update:modelValue', value: ModelValue): void
}>()
const model = useVModel(props, 'modelValue', emit)
function isRuleSelected(rule: FilterMatchRule) {
const { modelValue } = props
if (!modelValue?.selected)
return true
return modelValue.selected.includes(rule.name)
}
function toggleRule(rule: FilterMatchRule) {
const { rules } = props
if (!model?.value?.selected) {
model.value.selected = rules.map(r => r.name)
}
if (model.value.selected.includes(rule.name)) {
model.value.selected = model.value.selected.filter(t => t !== rule.name)
}
else {
model.value.selected.push(rule.name)
}
if (model?.value?.selected.length === props.rules.length) {
model.value.selected = null
}
}
function reverseSelect() {
if (model?.value?.selected?.length === props.rules.length) {
model.value.selected = null
}
else if (model?.value?.selected == null) {
model.value.selected = []
}
else {
model.value.selected = props.rules.map(r => r.name).filter(r => !model.value.selected?.includes(r))
}
}
function unselectToggle() {
if (model?.value?.selected?.length === 0) {
model.value.selected = null
}
else {
model.value.selected = []
}
}
</script>
<template>
<div flex="col gap-2" max-w-90vw min-w-30vw border="~ base rounded-xl" bg-glass>
<slot name="search">
<div v-if="modelValue.search !== false" class="flex items-center">
<input
v-model="model.search"
p2 px4
w-full
style="outline: none"
placeholder="Search"
>
<slot name="search-end" />
</div>
</slot>
<div v-if="rules.length" :class="selectedContainerClass" flex="~ gap-2 wrap" p2 border="t base">
<label
v-for="rule of rules"
:key="rule.name"
border="~ base rounded-md" px2 py1
flex="~ items-center gap-1"
select-none
:title="rule.description"
:class="isRuleSelected(rule) ? 'bg-active' : 'grayscale op50'"
>
<input
type="checkbox"
mr1
:checked="isRuleSelected(rule)"
@change="toggleRule(rule)"
>
<div :class="rule.icon" icon-catppuccin />
<div text-sm>{{ rule.description || rule.name }}</div>
</label>
<button
rounded-md p1
flex="~ items-center gap-1"
select-none
hover="bg-active"
title="Reverse Selection"
@click="reverseSelect"
>
<div op75 i-ph-selection-background-duotone />
</button>
<button
rounded-md p1
flex="~ items-center gap-1"
select-none
hover="bg-active"
:title="model.selected?.length === 0 ? 'Select All' : 'Unselect All'"
@click="unselectToggle"
>
<div v-if="model.selected?.length === 0" op75 i-ph-selection-slash-duotone />
<div v-else op75 i-ph-selection-plus-duotone />
</button>
</div>
<slot />
</div>
</template>