Skip to content

Commit 39efdbe

Browse files
committed
Add active-filters component
1 parent f3cc963 commit 39efdbe

File tree

2 files changed

+118
-37
lines changed

2 files changed

+118
-37
lines changed

js/Components/Table.vue

Lines changed: 57 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,12 @@
109109
/>
110110
</slot>
111111

112+
<TableActiveFilters
113+
v-if="queryBuilderProps.hasEnabledFilters"
114+
:filters="queryBuilderProps.filters"
115+
:on-filter-change="changeFilterValue"
116+
/>
117+
112118
<slot
113119
name="tableWrapper"
114120
:meta="resourceMeta"
@@ -195,11 +201,12 @@ import HeaderCell from "./HeaderCell.vue";
195201
import TableAddSearchRow from "./TableAddSearchRow.vue";
196202
import TableColumns from "./TableColumns.vue";
197203
import TableFilter from "./TableFilter.vue";
204+
import TableActiveFilters from "./TableActiveFilters.vue";
198205
import TableGlobalSearch from "./TableGlobalSearch.vue";
199206
import TableSearchRows from "./TableSearchRows.vue";
200207
import TableReset from "./TableReset.vue";
201208
import TableWrapper from "./TableWrapper.vue";
202-
import { computed, onMounted, ref, watch, onUnmounted, getCurrentInstance, Transition } from "vue";
209+
import { computed, getCurrentInstance, onMounted, onUnmounted, provide, ref, Transition, watch } from "vue";
203210
import qs from "qs";
204211
import clone from "lodash-es/clone";
205212
import filter from "lodash-es/filter";
@@ -271,8 +278,21 @@ const props = defineProps({
271278
},
272279
required: false,
273280
},
281+
282+
activeClasses: {
283+
type: Object,
284+
required: false,
285+
default() {
286+
return {
287+
text: "text-green-400",
288+
border: "border-green-300"
289+
};
290+
}
291+
}
274292
});
275293
294+
provide("activeClasses", props.activeClasses);
295+
276296
const app = getCurrentInstance();
277297
const $inertia = app ? app.appContext.config.globalProperties.$inertia : props.inertia;
278298
@@ -290,7 +310,7 @@ const queryBuilderProps = computed(() => {
290310
291311
const queryBuilderData = ref(queryBuilderProps.value);
292312
293-
const pageName = computed(() =>{
313+
const pageName = computed(() => {
294314
return queryBuilderProps.value.pageName;
295315
});
296316
@@ -299,19 +319,19 @@ const forcedVisibleSearchInputs = ref([]);
299319
const tableFieldset = ref(null);
300320
301321
const hasOnlyData = computed(() => {
302-
if(queryBuilderProps.value.hasToggleableColumns) {
322+
if (queryBuilderProps.value.hasToggleableColumns) {
303323
return false;
304324
}
305325
306-
if(queryBuilderProps.value.hasFilters) {
326+
if (queryBuilderProps.value.hasFilters) {
307327
return false;
308328
}
309329
310-
if(queryBuilderProps.value.hasSearchInputs) {
330+
if (queryBuilderProps.value.hasSearchInputs) {
311331
return false;
312332
}
313333
314-
if(queryBuilderProps.value.globalSearch) {
334+
if (queryBuilderProps.value.globalSearch) {
315335
return false;
316336
}
317337
@@ -320,26 +340,26 @@ const hasOnlyData = computed(() => {
320340
});
321341
322342
const resourceData = computed(() => {
323-
if(Object.keys(props.resource).length === 0){
343+
if (Object.keys(props.resource).length === 0) {
324344
return props.data;
325345
}
326346
327-
if("data" in props.resource) {
347+
if ("data" in props.resource) {
328348
return props.resource.data;
329349
}
330350
331351
return props.resource;
332352
});
333353
334354
const resourceMeta = computed(() => {
335-
if(Object.keys(props.resource).length === 0){
355+
if (Object.keys(props.resource).length === 0) {
336356
return props.meta;
337357
}
338358
339-
if("links" in props.resource && "meta" in props.resource) {
340-
if(Object.keys(props.resource.links).length === 4
341-
&& "next" in props.resource.links
342-
&& "prev" in props.resource.links) {
359+
if ("links" in props.resource && "meta" in props.resource) {
360+
if (Object.keys(props.resource.links).length === 4
361+
&& "next" in props.resource.links
362+
&& "prev" in props.resource.links) {
343363
return {
344364
...props.resource.meta,
345365
next_page_url: props.resource.links.next,
@@ -348,19 +368,19 @@ const resourceMeta = computed(() => {
348368
}
349369
}
350370
351-
if("meta" in props.resource) {
371+
if ("meta" in props.resource) {
352372
return props.resource.meta;
353373
}
354374
355375
return props.resource;
356376
});
357377
358378
const hasData = computed(() => {
359-
if(resourceData.value.length > 0){
379+
if (resourceData.value.length > 0) {
360380
return true;
361381
}
362382
363-
if(resourceMeta.value.total > 0) {
383+
if (resourceMeta.value.total > 0) {
364384
return true;
365385
}
366386
@@ -380,15 +400,15 @@ function showSearchInput(key) {
380400
}
381401
382402
const canBeReset = computed(() => {
383-
if(forcedVisibleSearchInputs.value.length > 0){
403+
if (forcedVisibleSearchInputs.value.length > 0) {
384404
return true;
385405
}
386406
387407
const queryStringData = qs.parse(location.search.substring(1));
388408
389409
const page = queryStringData[pageName.value];
390410
391-
if(page > 1) {
411+
if (page > 1) {
392412
return true;
393413
}
394414
@@ -398,11 +418,11 @@ const canBeReset = computed(() => {
398418
forEach(["filter", "columns", "cursor", "sort"], (key) => {
399419
const value = queryStringData[prefix + key];
400420
401-
if(key === "sort" && value === queryBuilderProps.value.defaultSort) {
421+
if (key === "sort" && value === queryBuilderProps.value.defaultSort) {
402422
return;
403423
}
404424
405-
if(value !== undefined) {
425+
if (value !== undefined) {
406426
dirty = true;
407427
}
408428
});
@@ -438,7 +458,7 @@ function changeSearchInputValue(key, value) {
438458
clearTimeout(debounceTimeouts[key]);
439459
440460
debounceTimeouts[key] = setTimeout(() => {
441-
if(visitCancelToken.value && props.preventOverlappingRequests){
461+
if (visitCancelToken.value && props.preventOverlappingRequests) {
442462
visitCancelToken.value.cancel();
443463
}
444464
@@ -509,7 +529,7 @@ function getColumnsForQuery() {
509529
return column.key;
510530
}).sort();
511531
512-
if (isEqual(visibleColumnKeys, queryBuilderProps.value.defaultVisibleToggleableColumns)){
532+
if (isEqual(visibleColumnKeys, queryBuilderProps.value.defaultVisibleToggleableColumns)) {
513533
return {};
514534
}
515535
@@ -522,11 +542,11 @@ function dataForNewQueryString() {
522542
523543
const queryData = {};
524544
525-
if(Object.keys(filterForQuery).length > 0) {
545+
if (Object.keys(filterForQuery).length > 0) {
526546
queryData.filter = filterForQuery;
527547
}
528548
529-
if(Object.keys(columnsForQuery).length > 0) {
549+
if (Object.keys(columnsForQuery).length > 0) {
530550
queryData.columns = columnsForQuery;
531551
}
532552
@@ -535,20 +555,20 @@ function dataForNewQueryString() {
535555
const sort = queryBuilderData.value.sort;
536556
const perPage = queryBuilderData.value.perPage;
537557
538-
if(cursor) {
558+
if (cursor) {
539559
queryData.cursor = cursor;
540560
}
541561
542-
if(page > 1) {
562+
if (page > 1) {
543563
queryData.page = page;
544564
}
545565
546-
if(perPage > 1) {
566+
if (perPage > 1) {
547567
queryData.perPage = perPage;
548568
}
549569
550570
551-
if(sort) {
571+
if (sort) {
552572
queryData.sort = sort;
553573
}
554574
@@ -566,10 +586,10 @@ function generateNewQueryString() {
566586
567587
delete queryStringData[pageName.value];
568588
569-
forEach(dataForNewQueryString(), (value, key) =>{
570-
if(key === "page") {
589+
forEach(dataForNewQueryString(), (value, key) => {
590+
if (key === "page") {
571591
queryStringData[pageName.value] = value;
572-
} else if(key === "perPage") {
592+
} else if (key === "perPage") {
573593
queryStringData.perPage = value;
574594
} else {
575595
queryStringData[prefix + key] = value;
@@ -600,7 +620,7 @@ const isVisiting = ref(false);
600620
const visitCancelToken = ref(null);
601621
602622
function visit(url) {
603-
if(!url) {
623+
if (!url) {
604624
return;
605625
}
606626
@@ -611,7 +631,7 @@ function visit(url) {
611631
replace: true,
612632
preserveState: true,
613633
preserveScroll: props.preserveScroll !== false,
614-
onBefore(){
634+
onBefore() {
615635
isVisiting.value = true;
616636
},
617637
onCancelToken(cancelToken) {
@@ -621,12 +641,12 @@ function visit(url) {
621641
isVisiting.value = false;
622642
},
623643
onSuccess() {
624-
if("queryBuilderProps" in $inertia.page.props){
644+
if ("queryBuilderProps" in $inertia.page.props) {
625645
queryBuilderData.value.cursor = queryBuilderProps.value.cursor;
626646
queryBuilderData.value.page = queryBuilderProps.value.page;
627647
}
628648
629-
if(props.preserveScroll === "table-top") {
649+
if (props.preserveScroll === "table-top") {
630650
const offset = -8;
631651
const top = tableFieldset.value.getBoundingClientRect().top + window.pageYOffset + offset;
632652
@@ -640,7 +660,7 @@ function visit(url) {
640660
}
641661
642662
watch(queryBuilderData, () => {
643-
visit(location.pathname + "?" + generateNewQueryString());
663+
visit(location.pathname + "?" + generateNewQueryString());
644664
}, { deep: true });
645665
646666
const inertiaListener = () => {
@@ -658,7 +678,7 @@ onUnmounted(() => {
658678
//
659679
660680
function sortBy(column) {
661-
if(queryBuilderData.value.sort == column) {
681+
if (queryBuilderData.value.sort == column) {
662682
queryBuilderData.value.sort = `-${column}`;
663683
} else {
664684
queryBuilderData.value.sort = column;

js/Components/TableActiveFilters.vue

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<template>
2+
<div class="flex items-center justify-start my-3 text-sm">
3+
<div class="">
4+
<svg
5+
xmlns="http://www.w3.org/2000/svg"
6+
class="h-5 w-5 text-gray-300"
7+
viewBox="0 0 20 20"
8+
fill="currentColor"
9+
>
10+
<path
11+
fill-rule="evenodd"
12+
d="M3 3a1 1 0 011-1h12a1 1 0 011 1v3a1 1 0 01-.293.707L12 11.414V15a1 1 0 01-.293.707l-2 2A1 1 0 018 17v-5.586L3.293 6.707A1 1 0 013 6V3z"
13+
clip-rule="evenodd"
14+
/>
15+
</svg>
16+
</div>
17+
18+
<button
19+
v-for="(filter) in filters.filter((filter) => filter.value)"
20+
:key="filter.label"
21+
class="block group ml-3 flex items-center justify-between px-2 py-1 rounded bg-gray-100"
22+
@click="onFilterChange(filter.key, null)"
23+
>
24+
<span class="capitalize text-gray-500">{{ filter.label.replace('_', ' ') }}</span>:
25+
<span class="ml-1 group-hover:line-through">{{ filter.options[filter.value] }}</span>
26+
27+
<svg
28+
:class="`group-hover:${activeClasses.text}`"
29+
xmlns="http://www.w3.org/2000/svg"
30+
class="h-4 w-4 ml-1 text-gray-400"
31+
viewBox="0 0 20 20"
32+
fill="currentColor"
33+
>
34+
<path
35+
fill-rule="evenodd"
36+
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
37+
clip-rule="evenodd"
38+
/>
39+
</svg>
40+
</button>
41+
</div>
42+
</template>
43+
44+
<script setup>
45+
import { inject } from "vue";
46+
47+
defineProps({
48+
filters: {
49+
type: Object,
50+
required: true,
51+
},
52+
53+
onFilterChange: {
54+
type: Function,
55+
required: true,
56+
},
57+
});
58+
59+
const activeClasses = inject("activeClasses");
60+
61+
</script>

0 commit comments

Comments
 (0)