Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@
},
"dependencies": {
"@graphql-tools/schema": "10.0.0",
"@headlessui/react": "^1.7.17",
"@heroicons/react": "^2.0.18",
"@radix-ui/react-aspect-ratio": "1.0.2",
"@radix-ui/react-icons": "1.3.0",
"@reach/router": "1.3.4",
"@tailwindcss/forms": "^0.5.6",
"@weknow/gatsby-remark-twitter": "0.2.3",
"assert": "2.0.0",
"clsx": "1.2.1",
Expand Down
124 changes: 124 additions & 0 deletions src/components/Conf/Schedule/Filters.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import React from "react"
import { Menu, Popover, Transition } from "@headlessui/react"
import { ChevronDownIcon, XMarkIcon } from "@heroicons/react/20/solid"
import clsx from "clsx"

type FiltersProps = {
categories: Array<{ name: string; options: string[] }>
filterState: Record<string, string[]>
onFilterChange: (category: string, option: string, checked: boolean) => void
onReset: () => void
}

export default function Filters({
categories,
filterState,
onFilterChange,
onReset,
}: FiltersProps) {
return (
<div className="">
<div aria-labelledby="filter-heading">
<div className="border-b border-gray-200 pb-4">
<div className="flex items-center justify-between">
{Object.values(filterState).flat().length > 0 && (
<button
onClick={onReset}
className="cursor-pointer flex items-center gap-x-2 px-2 py-1 bg-gray-200 hover:bg-gray-300 rounded-md text-sm font-medium text-gray-700 hover:text-gray-900"
>
Reset filters <XMarkIcon className="h-4 w-4 inline-block" />
</button>
)}
<Menu as="div" className="relative inline-block text-left">
<Transition
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<Menu.Items className="absolute left-0 z-10 mt-2 w-40 origin-top-left rounded-md shadow-2xl ring-1 ring-black ring-opacity-5 focus:outline-none">
<div className="py-1">
{categories.map(option => (
<Menu.Item key={option.name}>
<span
className={clsx(
filterState[option.name].length > 0
? "font-medium text-gray-900"
: "text-gray-500"
)}
>
{option.name}
</span>
</Menu.Item>
))}
</div>
</Menu.Items>
</Transition>
</Menu>

<div className="">
<div className="flow-root">
<Popover.Group className="flex items-baseline space-x-8">
{categories.map((section, sectionIdx) => (
<Popover
as="div"
key={section.name}
id={`desktop-menu-${sectionIdx}`}
className="relative inline-block text-left"
>
<div>
<Popover.Button className="bg-inherit p-1 px-2 group inline-flex items-center justify-center text-sm font-medium text-gray-700 hover:text-gray-900">
<span>{section.name}</span>
{filterState[section.name].length ? (
<span className="ml-1.5 rounded bg-gray-200 px-1.5 py-0.5 text-xs font-semibold tabular-nums text-gray-700">
{filterState[section.name].length}
</span>
) : null}
<ChevronDownIcon
className="-mr-1 ml-1 h-5 w-5 shrink-0 text-gray-400 group-hover:text-gray-500"
aria-hidden="true"
/>
</Popover.Button>
</div>

<Popover.Panel className="absolute right-0 z-10 mt-2 origin-top-right rounded-md bg-white p-4 shadow-lg border border-black focus:outline-none">
<form className="space-y-4 border border-black">
{section.options.map((option, optionIdx) => (
<div key={option} className="flex items-center">
<input
id={`filter-${section.name}-${optionIdx}`}
name={`${section.name}[]`}
defaultValue={option}
onChange={e => {
const { checked, value } = e.target
onFilterChange(section.name, value, checked)
}}
checked={filterState[section.name].includes(
option
)}
type="checkbox"
className="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
/>
<label
htmlFor={`filter-${section.name}-${optionIdx}`}
className="ml-3 whitespace-nowrap pr-6 text-sm font-medium text-gray-900"
>
{option}
</label>
</div>
))}
</form>
</Popover.Panel>
</Popover>
))}
</Popover.Group>
</div>
</div>
</div>
</div>
</div>
</div>
)
}
Loading