Skip to content

Commit

Permalink
make channel select searchable
Browse files Browse the repository at this point in the history
closes #107
  • Loading branch information
merlinfuchs committed Jan 17, 2024
1 parent f3df5cf commit d1ee3cb
Showing 1 changed file with 55 additions and 30 deletions.
85 changes: 55 additions & 30 deletions embedg-app/src/components/ChannelSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
ChevronDownIcon,
} from "@heroicons/react/24/outline";
import clsx from "clsx";
import { useMemo, useState } from "react";
import { useMemo, useRef, useState } from "react";
import { useGuildChannelsQuery } from "../api/queries";
import ClickOutsideHandler from "./ClickOutsideHandler";

Expand All @@ -28,13 +28,26 @@ function canSelectChannelType(type: number) {
export function ChannelSelect({ guildId, channelId, onChange }: Props) {
const { data } = useGuildChannelsQuery(guildId);

const inputRef = useRef<HTMLInputElement>(null);

const [open, innerSetOpen] = useState(false);
const [query, setQuery] = useState("");

function setOpen(open: boolean) {
innerSetOpen(open);
if (open) {
setTimeout(() => inputRef.current?.focus(), 0);
} else {
inputRef.current?.blur();
setQuery("");
}
}

function selectChannel(channelId: string) {
onChange(channelId);
setOpen(false);
}

const [open, setOpen] = useState(false);

const channels = useMemo(() => {
const rawChannels = data?.success ? data.data : [];

Expand Down Expand Up @@ -115,6 +128,15 @@ export function ChannelSelect({ guildId, channelId, onChange }: Props) {
return res;
}, [data]);

const filteredChannels = useMemo(() => {
if (!query) return channels;

const q = query.toLowerCase();
if (!q) return channels;

return channels.filter((c) => c.id === q || c.name.includes(q));
}, [channels, query]);

const channel = useMemo(
() => channels.find((c) => c.id === channelId),
[channels, channelId]
Expand All @@ -123,38 +145,41 @@ export function ChannelSelect({ guildId, channelId, onChange }: Props) {
return (
<ClickOutsideHandler onClickOutside={() => setOpen(false)}>
<div className="px-3 h-10 flex items-center rounded bg-dark-2 relative select-none">
<div
role="button"
onClick={() => setOpen((prev) => !prev)}
className="flex-auto"
>
{channel ? (
<div className="flex items-center space-x-2 cursor-pointer w-full">
{channel.type === 15 ? (
<ChatBubbleLeftRightIcon className="h-5 w-5 text-gray-300" />
) : (
<div className="text-xl italic text-gray-400 font-light pl-1">
#
<div role="button" onClick={() => setOpen(!open)} className="flex-auto">
<input
type="text"
ref={inputRef}
value={query}
onChange={(e) => setQuery(e.target.value)}
className={clsx(
"text-gray-300 flex-auto bg-dark-2 focus:outline-none",
open ? "hidden md:block" : "hidden"
)}
/>
<div className={open ? "md:hidden" : ""}>
{channel ? (
<div className="flex items-center space-x-2 cursor-pointer w-full">
{channel.type === 15 ? (
<ChatBubbleLeftRightIcon className="h-5 w-5 text-gray-300" />
) : (
<div className="text-xl italic text-gray-400 font-light pl-1">
#
</div>
)}
<div className="text-gray-300 flex-auto truncate">
{channel.name}
</div>
)}
<div className="text-gray-300 flex-auto truncate">
{channel.name}
<ChevronDownIcon className="text-white w-5 h-5 flex-none transition-transform" />
</div>
<ChevronDownIcon
className={clsx(
"text-white w-5 h-5 flex-none transition-transform",
open && "rotate-180"
)}
/>
</div>
) : (
<div className="text-gray-300">Select channel</div>
)}
) : (
<div className="text-gray-300">Select channel</div>
)}
</div>
</div>
{open && (
<div className="absolute bg-dark-2 top-14 left-0 rounded shadow-lg w-full border-2 border-dark-2 z-10 max-h-48 overflow-y-auto overflow-x-none">
{channels.length ? (
channels.map((c) => (
{filteredChannels.length ? (
filteredChannels.map((c) => (
<div
key={c.id}
className={clsx(
Expand Down

0 comments on commit d1ee3cb

Please sign in to comment.