Explorar o código

replace SelectButton with ButtonGroup, replace filter-related function props with a field prop, fix min-height, change reset button label from Clear to Reset, watch matchMode property on model

Jason Gorst hai 1 mes
pai
achega
1fa34a6da8
Modificáronse 1 ficheiros con 80 adicións e 60 borrados
  1. 80 60
      app/components/TextFilter.vue

+ 80 - 60
app/components/TextFilter.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="flex min-h-56.5 flex-col justify-between">
+  <div class="flex min-h-57 flex-col justify-between">
     <div class="flex flex-col gap-2">
       <InputText
         v-model="model.value"
@@ -8,34 +8,44 @@
         placeholder="Filter&hellip;"
       />
 
-      <div class="w-full bg-primary-200 px-2 py-1">
-        {{ matchMode }}
+      <div
+        class="flex justify-center rounded-md border border-primary bg-primary px-2 py-1
+          text-primary-contrast transition-colors duration-200 select-none"
+        :class="[
+          hovered && 'border-primary-emphasis bg-primary-emphasis',
+          activated && 'border-primary-emphasis-alt bg-primary-emphasis-alt'
+        ]"
+      >
+        {{ badge }}
       </div>
 
-      <SelectButton
-        v-model="model.matchMode"
-        :options="matchModeOptions"
-        optionLabel="name"
-        optionValue="value"
-        dataKey="value"
-        :pt="{
-          root: `*:rounded-none *:not-last:border-r-0 *:first:rounded-s-md *:last:rounded-e-md
-          *:focus-visible:relative *:focus-visible:z-10`,
-          pcToggleButton: {
-            root: `grow border-primary-200! bg-transparent! p-0! text-primary!
-            hover:border-primary-300! hover:bg-primary-50! dark:border-primary-700!
-            dark:hover:border-primary-600! dark:hover:bg-primary/5!
-            p-checked:border-primary-400! p-checked:bg-primary-100!
-            dark:p-checked:border-primary-500! dark:p-checked:bg-primary/15!`,
-            content: 'px-0! py-0.5! p-checked:bg-transparent!'
-          }
-        }"
-      >
-        <!--suppress VueUnrecognizedSlot -->
-        <template #option="slotProps">
-          <Icon :name="slotProps.option.icon" />
+      <ButtonGroup class="flex flex-row">
+        <template v-for="{ name, icon, matchMode } in matchModes">
+          <Button
+            v-if="!isCurrentMatchMode(matchMode)"
+            size="sm"
+            variant="outlined"
+            class="grow px-0! py-1.5! hover:bg-primary/15"
+            @click="changeMatchMode(matchMode)"
+            @pointerdown="activate()"
+            @pointerup="deactivate()"
+            @pointerenter="hover(name)"
+            @pointerleave="unhover()"
+          >
+            <Icon :name="icon" />
+          </Button>
+
+          <div
+            v-else
+            class="relative inline-flex grow items-center justify-center gap-2
+              overflow-hidden rounded-md border border-primary-400 bg-primary-100 px-0 py-1.5
+              text-sm text-primary transition-colors duration-200 select-none
+              dark:border-primary-500 dark:bg-primary/15"
+          >
+            <Icon :name="icon" />
+          </div>
         </template>
-      </SelectButton>
+      </ButtonGroup>
     </div>
 
     <Button
@@ -43,55 +53,65 @@
       variant="outlined"
       size="small"
       fluid
-      :disabled="!hasFilter()"
-      @click="resetFilter"
+      :disabled="!hasFilterFor(props.field)"
+      @click="resetFilterFor(props.field)"
     >
-      Clear
+      Reset
     </Button>
   </div>
 </template>
 
 <script setup>
-import { FilterMatchMode } from "@primevue/core/api"
-
 const model = defineModel()
 
 const props = defineProps({
-  filterCallback: {
-    type: Function,
-    required: true
-  },
-
-  hasFilter: {
-    type: Function,
-    required: true
-  },
-
-  resetFilter: {
-    type: Function,
+  field: {
+    type: String,
     required: true
   }
 })
 
-const matchModeOptions = ref([
-  {
-    name: "Starts with",
-    icon: "ph:arrow-line-left",
-    value: FilterMatchMode.STARTS_WITH
-  },
-  {
-    name: "Contains",
-    icon: "ph:arrows-out-line-horizontal",
-    value: FilterMatchMode.CONTAINS
+const { hasFilterFor, resetFilterFor } = useFiltersStore()
+
+const badge = ref()
+const hovered = ref(false)
+const activated = ref(false)
+
+watch(
+  () => model.value.matchMode,
+  (matchMode) => {
+    badge.value = nameFromMatchMode(matchMode)
+    hovered.value = false
   },
-  {
-    name: "Ends with",
-    icon: "ph:arrow-line-right",
-    value: FilterMatchMode.ENDS_WITH
-  }
-])
+  { immediate: true }
+)
+
+function isCurrentMatchMode(matchMode) {
+  return matchMode === model.value.matchMode
+}
+
+function hover(name) {
+  hovered.value = true
+  badge.value = name
+}
+
+function unhover() {
+  hovered.value = false
+  badge.value = nameFromMatchMode(model.value.matchMode)
+}
+
+function activate() {
+  activated.value = true
+}
+
+function deactivate() {
+  activated.value = false
+}
 
-const matchMode = ref("Contains")
+function changeMatchMode(matchMode) {
+  model.value.matchMode = matchMode
+  deactivate()
+}
 </script>
 
 <style scoped></style>