Skip to content

Commit

Permalink
Fabulous filters 💅 (#560)
Browse files Browse the repository at this point in the history
  • Loading branch information
JimmyHoenderdaal authored Sep 6, 2024
1 parent 7ffc3e1 commit 8d54625
Show file tree
Hide file tree
Showing 10 changed files with 166 additions and 60 deletions.
1 change: 1 addition & 0 deletions resources/css/app.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@import 'components/vue-slider';
@import 'components/price-slider';
@import './theme-variables.css';
@import './components/pagination.css';

Expand Down
44 changes: 44 additions & 0 deletions resources/css/components/price-slider.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
div.vue-slider {
@apply mt-5 mb-3.5 max-w-sm;
}

div.vue-slider-process,
div.vue-slider-rail {
@apply h-2 bg-neutral !important;
}

div.vue-slider-rail {
@apply bg-highlight !important;
}

div.vue-slider .vue-slider-dot {
@apply size-6 !important;
}

div.vue-slider-dot-tooltip-inner {
@apply bg-white text-neutral border-border border px-1.5 !important;
}

span.vue-slider-dot-tooltip-text {
@apply font-medium font-sans text-neutral;
}

div.vue-slider-dot-tooltip::before {
@apply hidden;
}

div.vue-slider-dot .vue-slider-dot-handle {
@apply border border-border shadow;
}

div.vue-slider-tooltip-wrap.vue-slider-tooltip-top {
@apply font-sans;
}

.price-input {
@apply space-x-3;
}

.vue-slider-component.vue-slider-horizontal {
@apply mt-5;
}
14 changes: 14 additions & 0 deletions resources/views/components/filter/heading.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<input class="peer hidden" type="checkbox" checked :set="id = Math.random().toString(36).slice(2)" :id="id" />

<label class="flex cursor-pointer items-center justify-between gap-x-2 border-t pb-2.5 pt-4 text-neutral peer-checked:[&>.chevron]:rotate-180" :for="id">
<span class="block font-sans text-base font-semibold text-neutral">
@{{ filter?.name?.replace('_', ' ') }}
</span>

<x-heroicon-o-chevron-down class="size-4 chevron transition" />
</label>
<div class="peer-checked:*:-my-1 peer-checked:*:py-1 grid grid-rows-[0fr] transition-all peer-checked:grid-rows-[1fr]">
<div class="-mx-1 overflow-hidden px-1">
{{ $slot }}
</div>
</div>
6 changes: 3 additions & 3 deletions resources/views/components/slideover/index.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@
<x-tag v-on:reset="toggleScroll(false)" :is="$tag">
<input id="{{ 'close-' . $id }}" class="hidden" type="reset">
@if (!$hasParent)
<input @checked($open) {{ $attributes->merge(['id' => $id, 'class' => 'peer hidden']) }} v-on:change="toggleScroll($event.target.checked)" type="checkbox">
<input @checked($open) id="{{ $id }}" class="peer hidden" v-on:change="toggleScroll($event.target.checked)" type="checkbox">
<label
v-bind:for="{{ $attributes->get('v-bind:id') ?? '\'' . $closeId . '\'' }}"
for="{{ $closeId }}"
class="pointer-events-none fixed inset-0 z-40 cursor-pointer bg-neutral/50 opacity-0 transition peer-checked:pointer-events-auto peer-checked:opacity-100"
></label>
@else
<input @checked($open) {{ $attributes->merge(['id' => $id, 'class' => 'peer hidden']) }} type="checkbox">
<input @checked($open) id="{{ $id }}" class="peer hidden" type="checkbox">
@endif
<div {{ $attributes->class([
'fixed inset-y-0 transition-all bg-white z-40 flex flex-col max-w-md w-full',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
{{ $title }}
</span>
@endif
<label v-bind:for="{{ $attributes->get('v-bind:id') ?? '\'' . $closeId . '\'' }}" class="absolute right-0 top-1/2 -translate-y-1/2 cursor-pointer text-white">
<label for="{{ $closeId }}" class="absolute right-0 top-1/2 -translate-y-1/2 cursor-pointer text-white">
<x-heroicon-o-x-mark class="size-6" />
</label>
</div>
Expand Down
2 changes: 1 addition & 1 deletion resources/views/layouts/app.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
@config('design/head/includes')
</head>
<body class="text-neutral antialiased">
<div id="app" class="flex flex-col min-h-screen">
<div id="app" class="flex flex-col min-h-dvh">
@includeWhen(!request()->is('checkout'), 'rapidez::layouts.partials.header')
@includeWhen(request()->is('checkout'), 'rapidez::layouts.checkout.header')
<main>
Expand Down
36 changes: 22 additions & 14 deletions resources/views/listing/partials/filter/boolean.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,31 @@
v-else-if="filter.input == 'boolean'"
:component-id="filter.code"
:data-field="filter.code+(filter.type != 'int' ? '.keyword' : '')"
:inner-class="{
title: 'capitalize text-sm font-medium text-gray-900',
count: 'text-gray-400',
list: '!max-h-full',
label: 'ml-1 text-sm text-gray-600'
}"
:title="filter.name.replace('_', ' ')"
:react="{and: reactiveFilters}"
:show-search="false"
u-r-l-params
>
<span
slot="renderItem"
slot-scope="{ label, count }"
<div
slot="render"
class="relative pb-4"
slot-scope="{ data, handleChange, value }"
v-if="data.length > 0"
>
<template v-if="label">@lang('Yes')</template>
<template v-else>@lang('No')</template>
<span class="text-gray-600">(@{{ count }})</span>
</span>
<x-rapidez::filter.heading>
<ul class="flex flex-col gap-1">
<li class="flex" v-for="item in data">
<x-rapidez::checkbox
v-bind:checked="value[item.key]"
v-on:change="handleChange(item.key)"
>
<div class="font-sans font-medium text-sm items-center flex text-inactive" :class="{'text-neutral': value[item.key] == true}">
<template v-if="item.key">@lang('Yes')</template>
<template v-if="!item.key">@lang('No')</template>
<span class="block ml-0.5 text-xs">(@{{ item.doc_count }})</span>
</div>
</x-rapidez::checkbox>
</li>
</ul>
</x-rapidez::filter.heading>
</div>
</multi-list>
29 changes: 16 additions & 13 deletions resources/views/listing/partials/filter/price.blade.php
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
<dynamic-range-slider
v-if="filter.input == 'price'"
:component-id="filter.code"
:data-field="filter.code"
:title="filter.name.replace('_', ' ')"
:react="{and: ['query-filter']}"
:show-filter="false"
:inner-class="{
title: 'capitalize text-sm font-medium text-gray-900',
}"
:slider-options="{ dragOnClick: true, useKeyboard: false }"
u-r-l-params
></dynamic-range-slider>
<div v-if="filter.input == 'price'" class="relative pb-4">
<x-rapidez::filter.heading>
<dynamic-range-slider
:component-id="filter.code"
:data-field="filter.code"
:react="{and: ['query-filter']}"
:show-filter="false"
:slider-options="{ dragOnClick: true, useKeyboard: false }"
:inner-class="{
slider: '!pt-4 !mt-0 mx-2',
}"
u-r-l-params
>
</dynamic-range-slider>
</x-rapidez::filter.heading>
</div>
45 changes: 40 additions & 5 deletions resources/views/listing/partials/filter/select.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,49 @@
:component-id="filter.code"
:data-field="filter.code+'.keyword'"
:inner-class="{
title: 'capitalize font-semibold',
count: 'text-gray-400',
count: 'text-inactive',
list: '!max-h-full [&>li]:!h-auto',
label: 'text-gray-600 before:shrink-0'
label: 'text-inactive before:shrink-0'
}"
:title="filter.name.replace('_', ' ')"
:react="{and: filter.input == 'multiselect' ? reactiveFilters : reactiveFilters.filter(item => item != filter.code) }"
:query-format="filter.input == 'multiselect' ? 'and' : 'or'"
:show-search="false"
u-r-l-params
></multi-list>
>
<div slot="render" class="relative pb-4" slot-scope="{ data, handleChange, value }" v-if="data.length > 1">
<x-rapidez::filter.heading>
<toggler>
<ul class="flex flex-col gap-1" slot-scope="{ toggle, isOpen }">
<li
v-for="item, index in data"
v-if="index < 6 || isOpen"
:key="item._id"
class="flex justify-between text-base text-inactive"
>
<div class="flex">
<x-rapidez::checkbox
v-bind:checked="value[item.key]"
v-on:change="handleChange(item.key)"
>
<div class="font-sans font-medium text-inactive items-center text-sm flex" :class="{'text-neutral': value[item.key] == true}">
@{{ item.key }}
<span class="block ml-0.5 text-xs">(@{{ item.doc_count }})</span>
</div>
</x-rapidez::checkbox>
</div>
</li>
<li v-if="data.length > 6">
<button class="text-sm text-primary" @click="toggle">
<span v-if="isOpen" class="flex gap-x-4">
@lang('Less options')
</span>
<span v-else class="flex gap-x-4">
@lang('More options')
</span>
</button>
</li>
</ul>
</toggler>
</x-rapidez::filter.heading>
</div>
</multi-list>
47 changes: 24 additions & 23 deletions resources/views/listing/partials/filter/swatch.blade.php
Original file line number Diff line number Diff line change
@@ -1,37 +1,38 @@
<multi-list
v-else-if="filter.text_swatch || filter.visual_swatch"
:component-id="filter.code"
:data-field="filter.super ? 'super_' + filter.code : filter.code"
:data-field="filter.super ? 'super_' + filter.code : (filter.visual_swatch ? 'visual_' + filter.code : filter.code)"
:inner-class="{
title: 'capitalize text-sm font-medium text-gray-900',
list: '!max-h-full flex flex-wrap',
}"
:title="filter.name.replace('_', ' ')"
:react="{and: filter.input == 'multiselect' ? reactiveFilters : reactiveFilters.filter(item => item != filter.code) }"
:query-format="filter.input == 'multiselect' ? 'and' : 'or'"
:show-search="false"
:show-checkbox="false"
u-r-l-params
>
<div
v-if="filter.visual_swatch"
slot="renderItem"
slot-scope="{ label, isChecked }"
class="w-6 h-6 border-black mr-1 mb-1 rounded-full hover:opacity-75"
:class="isChecked ? 'border-2' : 'border'"
:style="{ background: $root.swatches[filter.code]?.options[label].swatch }"
>
<x-heroicon-o-check v-if="isChecked"/>
</div>

<div
v-else
slot="renderItem"
slot-scope="{ label, isChecked }"
class="border-black mr-1 mb-1 px-3 hover:opacity-75"
:class="isChecked ? 'border-2' : 'border'"
:style="{ background: $root.swatches[filter.code]?.options[label].swatch }"
>
@{{ $root.swatches[filter.code]?.options[label].swatch }}
<div slot="render" class="pb-4" slot-scope="{ data, value, handleChange }">
<x-rapidez::filter.heading>
<div class="flex flex-wrap gap-2 items-center my-1">
<template v-for="swatch in data">
<label
v-if="filter.visual_swatch"
class="size-6 ring-black/5 ring-1 ring-inset cursor-pointer flex items-center justify-center hover:opacity-75 rounded-full transition"
v-bind:class="{'outline-2 outline outline-black outline-offset-1' : value[swatch.key]}"
v-bind:style="{ background: $root.swatches[filter.code]?.options[swatch.key].swatch }"
>
<input type="checkbox" v-on:change="handleChange(swatch.key)" class="hidden" v-bind:checked="value[swatch.key]"/>
</label>
<label
v-else
class="border px-3 transition-all rounded cursor-pointer text-sm text-inactive font-medium"
v-bind:class="{'border-neutral text-neutral' : value[swatch.key]}"
>
@{{ $root.swatches[filter.code]?.options[swatch.key].swatch }}
<input type="checkbox" v-on:change="handleChange(swatch.key)" class="hidden" v-bind:checked="value[swatch.key]"/>
</label>
</template>
</div>
</x-rapidez::filter.heading>
</div>
</multi-list>

0 comments on commit 8d54625

Please sign in to comment.