Skip to content

Instantly share code, notes, and snippets.

@codemonkey76
Last active December 6, 2022 04:11
Show Gist options
  • Save codemonkey76/c227fe1809388111d57e0542b3b7081f to your computer and use it in GitHub Desktop.
Save codemonkey76/c227fe1809388111d57e0542b3b7081f to your computer and use it in GitHub Desktop.
@props([
'categories' => null,
'options' => []
])
<div class="relative" x-data="accordianDropdown({
categories: {{ $categories }},
options: {{ $options }}
})" tabindex="0">
<span x-show="selectedItem" class="absolute inset-y-0 left-0 pl-4 flex items-center text-cyan-600" x-html="getSelectedItemIcon()"></span>
<input id="combobox" x-ref="input" type="text" x-model="search" @keydown="startEditing()" class="w-full rounded-md border border-gray-300 bg-white py-2 pl-10 pr-12 shadow-sm focus:border-cyan-500 focus:outline-none focus:ring-1 focus:ring-cyan-500 sm:text-sm" role="combobox" aria-controls="options" aria-expanded="false">
<button @click="open=!open" type="button" class="absolute inset-y-0 right-0 flex items-center rounded-r-md px-2 focus:outline-none">
<svg class="h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M10 3a.75.75 0 01.55.24l3.25 3.5a.75.75 0 11-1.1 1.02L10 4.852 7.3 7.76a.75.75 0 01-1.1-1.02l3.25-3.5A.75.75 0 0110 3zm-3.76 9.2a.75.75 0 011.06.04l2.7 2.908 2.7-2.908a.75.75 0 111.1 1.02l-3.25 3.5a.75.75 0 01-1.1 0l-3.25-3.5a.75.75 0 01.04-1.06z" clip-rule="evenodd" />
</svg>
</button>
<ul x-show="open" class="absolute divide-y divide-gray-200 z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-slate-100 py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm" id="options" role="listbox">
<template x-for="category in categories">
<template x-if="getFilteredDestinationsByCategory(category.name).length">
<ul class="bg-white">
<li @click.prevent="category.open = !category.open" class="relative cursor-pointer select-none py-2 pl-10 pr-3 text-cyan-800 bg-slate-100" id="option-0" role="option" tabindex="-1">
<span class="block truncate font-bold" x-text="category.label"></span>
<span class="absolute inset-y-0 left-0 pl-4 flex items-center text-cyan-600" x-html="category.icon"></span>
<span class="absolute inset-y-0 right-0 pt-3 pr-3">
<span class="flex items-center justify-center transition" :class="category.open ? 'text-cyan-600 rotate-90' : 'text-slate-300'" x-html="icons.triangle"></span>
</span>
</li>
<ul x-show="category.open"
x-collapse
>
<template x-for="destination in getFilteredDestinationsByCategory(category.name)">
<li @click.prevent="selectItem(destination)" class="py-2 pl-4 cursor-pointer text-base hover:text-white hover:bg-cyan-600"><span x-text="destination.label"></span></li>
</template>
</ul>
</ul>
</template>
</template>
</ul>
</div>
export default (config) => ({
expanded: true,
open: false,
search: '',
selectedItem: null,
editing: true,
icons: {
triangle: '<svg class="h-3 w-3" fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path d="M73 39c-14.8-9.1-33.4-9.4-48.5-.9S0 62.6 0 80V432c0 17.4 9.4 33.4 24.5 41.9s33.7 8.1 48.5-.9L361 297c14.3-8.7 23-24.2 23-41s-8.7-32.2-23-41L73 39z"/></svg>',
},
categories: [],
init() {
this.categories = config.categories.map(({name, label, icon}) => ({
name,
label,
icon,
open: this.expanded
}))
this.options = config.options
},
options: [],
getDestinationsByCategory(category) {
return this.options.filter((option) => option.category === category)
},
getFilteredDestinationsByCategory(category) {
if (this.editing)
return this.options.filter((option => option.category === category && option.label.toLowerCase().indexOf(this.search.toLowerCase()) > -1))
return this.getDestinationsByCategory(category)
},
getCategoryByName(name) {
return this.categories.find((category) => category.name === name)
},
getSelectedItemIcon() {
if (!this.selectedItem) return false;
return this.getCategoryByName(this.selectedItem.category).icon
},
selectItem(destination) {
this.selectedItem = destination
this.search = destination.label
this.open = false
this.editing = false
},
onFocused() {
this.$refs.input.select()
this.open = true
},
onLostFocus() {
this.open = false
},
startEditing() {
this.categories.forEach((category) => { category.open = true})
this.open = true
this.editing = true
this.selectedItem = null
}
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment