Skip to content

Commit

Permalink
Move the filters to a modal on mobile and add a clear all filters button
Browse files Browse the repository at this point in the history
  • Loading branch information
ysbrandB committed Jun 21, 2024
1 parent 5471b15 commit 9b6ab30
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 42 deletions.
19 changes: 13 additions & 6 deletions resources/js/Components/Card.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
<script setup lang="ts">
const props = defineProps<{
color?: string;
}>();
const props = withDefaults(defineProps<{
color?: string,
additionalClasses?: string
}>(), {
additionalClasses: 'p-4 mx-2'
})
</script>
<template>
<div class="w-full my-2">
<div :class="color?`bg-${color}-100 dark:bg-${color}-900`:'bg-white dark:bg-gray-80'"
class="overflow-hidden shadow-sm rounded-lg h-full flex flex-col p-4 mx-2">
<div :class="[
color?`bg-${color}-100`:'bg-white',
color?`text-${color}-800`:'text-gray-800',
color?`dark:bg-${color}-900`:'dark:bg-gray-800',
props.additionalClasses?props.additionalClasses:'']"
class="overflow-hidden shadow-sm rounded-lg h-full flex flex-col">
<slot></slot>
</div>
</div>
</div>
</template>
2 changes: 1 addition & 1 deletion resources/js/Components/Modal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ const maxWidthClass = computed(() => {
class="mb-6 bg-white dark:bg-gray-800 rounded-lg overflow-hidden shadow-xl transform transition-all sm:w-full sm:mx-auto"
:class="maxWidthClass"
>
<slot v-if="show" />
<slot />
</div>
</Transition>
</div>
Expand Down
8 changes: 6 additions & 2 deletions resources/js/CustomComponents/AttributeFilter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,13 @@ defineExpose({
</script>
<template>
<div class="flex justify-items-center items-end mt-4 w-full">
<div class="bg-red-100 basis-1/3 grow"></div>
<div class="bg-red-100 basis-1/3 grow"></div>
<div class="text-2xl text-center basis-1/3 font-semibold grow">{{ capitalizeFirstLetter(title) }}</div>
<div class="grow basis-1/3 mb-1"> <pill v-if="checkedAttributesMap.size" class="cursor-pointer" @click="reset()" :color="'red'"> Clear all filters</pill> </div>
<div class="grow basis-1/3 mb-1">
<pill v-if="checkedAttributesMap.size" class="cursor-pointer" @click="reset()" :color="'red'"> Clear all
filters
</pill>
</div>
</div>
<div
class="mx-2 mt-1 flex flex-wrap text-sm font-medium text-gray-900 bg-white border border-gray-200 rounded-lg dark:bg-gray-700 dark:border-gray-600 dark:text-white">
Expand Down
16 changes: 16 additions & 0 deletions resources/js/CustomComponents/MountedTeleport.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<template>
<Teleport :to="to" v-if="isMounted" :disabled="disabled"><slot></slot></Teleport>
</template>

<script>
export default {
name: "MountedTeleport",
props: ['to', 'disabled'],
data() {
return {isMounted: false}
},
mounted() {
this.isMounted = true;
}
}
</script>
10 changes: 5 additions & 5 deletions resources/js/CustomComponents/TailwindWidth.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {computed, ComputedRef, ref} from "vue";
import {computed, ref} from "vue";
const screens = {
sm: 640,
md: 768,
Expand All @@ -11,16 +11,14 @@ export enum Breakpoints {
md = 'md',
lg = 'lg',
xl = 'xl',
all = 'all'
}
const w = ref(window.innerWidth);

const breakpoint = computed(()=>{
if ( w.value >= screens.sm && w.value <= screens.md ) return Breakpoints.sm
if (w.value <= screens.md ) return Breakpoints.sm
else if (w.value >= screens.md && w.value <= screens.lg) return Breakpoints.md
else if (w.value >= screens.lg && w.value <= screens.xl) return Breakpoints.lg
else if (w.value >= screens.xl) return Breakpoints.xl
else return Breakpoints.all
else return Breakpoints.xl
})
const debounce = function(func: any, wait: number) {
let timeout: number | undefined
Expand All @@ -45,4 +43,6 @@ window.addEventListener(
false
)

w.value = window.innerWidth
console.log(w.value, breakpoint.value)
export default breakpoint
84 changes: 56 additions & 28 deletions resources/js/Pages/Items/Index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import ItemCard from "@/Pages/Items/ItemCard.vue";
import Modal from "@/Components/Modal.vue";
import SecondaryButton from "@/Components/SecondaryButton.vue";
import SelectedItemDropdown from "@/CustomComponents/SelectedItemDropdown.vue";
import breakpoints, {Breakpoints} from '../../CustomComponents/TailwindWidth'
import {Breakpoints} from '@/CustomComponents/TailwindWidth'
import MountedTeleport from "@/CustomComponents/MountedTeleport.vue";
import breakpoint from "../../CustomComponents/TailwindWidth";
const props = defineProps<{
Expand Down Expand Up @@ -65,7 +67,7 @@ const filter: Ref<typeof AttributeFilter | null> = ref(null);
const removeItemFromSelected = (id: number) => {
const item = Array.from(selectedItems.value).find((item) => item.id === id);
if(item) {
if (item) {
selectedItems.value.delete(item);
}
}
Expand All @@ -76,7 +78,17 @@ const addItemToSelected = (id: number) => {
selectedItems.value.add(item);
}
}
const phoneModalOpen = ref(false);
const lastBreakpoint = ref(breakpoint.value);
watch(breakpoint, (br) => {
if (breakpoint.value === Breakpoints.sm && lastBreakpoint.value !== Breakpoints.sm) {
phoneModalOpen.value = false;
lastBreakpoint.value = Breakpoints.sm;
} else {
lastBreakpoint.value = breakpoint.value;
}
});
const shouldModal = computed(() => breakpoint.value === Breakpoints.sm);
</script>

<template>
Expand All @@ -102,35 +114,46 @@ const addItemToSelected = (id: number) => {
</div>
</template>

<section class="w-full h-full mx-auto">
<section class="relative w-full h-full mx-auto">
<button class="fixed bottom-0 right-0" v-if="shouldModal"
@click="phoneModalOpen=true">
<card class="font-bold" :additional-classes="'mr-2 shadow p-2 border-dashed border-2 border-gray-700'">
Filters
</card>
</button>
<div class="grid grid-cols-3 md:grid-cols-6 lg:grid-cols-12 gap-4 max-w-[90%] mx-auto">
<div class="col-span-3 md:pt-0 mt-2">
<card class="">
<div class="w-full text-center">
<attribute-filter
ref="filter"
@update="reloadWithFilters"
:attribute-types="attributeTypes"
:initial-filters="initialFilters"/>
</div>
</card>
<MountedTeleport to="#attributeModal" :disabled="!shouldModal">
<card class="">
<div class="w-full text-center">
<attribute-filter
ref="filter"
@update="reloadWithFilters"
:attribute-types="attributeTypes"
:initial-filters="initialFilters"/>
</div>
</card>
</MountedTeleport>
</div>
<div class="lg:col-span-9 col-span-3">
<div class="grid lg:grid-cols-4 grid-cols-2 gap-4 mt-4">
<item-card :item="item" v-for="item in items">
<template #qr>
<button v-if="selectedItemIds.find((id) => id === item.id)" @click="removeItemFromSelected(item.id)"
class="bg-red-600 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-red-500 active:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 transition ease-in-out duration-150"
style="border-radius:.5em;font-size: 1.1em; width:3.5em; height:3em; align-self: flex-end;">
-
</button>
<button v-else @click="addItemToSelected(item.id)"
class="bg-grey-100 dark:bg-gray-800 border border-grey-300 dark:border-gray-500 font-semibold text-xs text-gray-700 dark:text-gray-300 uppercase tracking-widest shadow-sm hover:bg-emerald-100 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 disabled:opacity-25 transition ease-in-out duration-150"
style="border-radius:.5em;font-size: 1.1em; width:3.5em; height:3em; align-self: flex-end;">
+
</button>
</template>
</item-card>
<div class="grid lg:grid-cols-4 md:grid-cols-2 grid-cols-1 gap-4 mt-4">
<div class="md:mx-0 md:max-w-full max-w-[70%] w-full mx-auto" v-for="item in items">
<item-card :item="item">
<template #qr>
<button v-if="selectedItemIds.find((id) => id === item.id)"
@click="removeItemFromSelected(item.id)"
class="bg-red-600 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-red-500 active:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 transition ease-in-out duration-150"
style="border-radius:.5em;font-size: 1.1em; width:3.5em; height:3em; align-self: flex-end;">
-
</button>
<button v-else @click="addItemToSelected(item.id)"
class="bg-grey-100 dark:bg-gray-800 border border-grey-300 dark:border-gray-500 font-semibold text-xs text-gray-700 dark:text-gray-300 uppercase tracking-widest shadow-sm hover:bg-emerald-100 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 disabled:opacity-25 transition ease-in-out duration-150"
style="border-radius:.5em;font-size: 1.1em; width:3.5em; height:3em; align-self: flex-end;">
+
</button>
</template>
</item-card>
</div>
</div>
</div>
</div>
Expand Down Expand Up @@ -201,5 +224,10 @@ const addItemToSelected = (id: number) => {
</div>
</div>
</modal>
<modal :show="shouldModal && phoneModalOpen" @close="phoneModalOpen=false">
<div class="attributeModal" id="attributeModal">
<!-- the attribute filter will be put here when the screen is in the mobile range-->
</div>
</modal>
</AuthenticatedLayout>
</template>

0 comments on commit 9b6ab30

Please sign in to comment.