Skip to content

Commit

Permalink
Introduce keyboard navigation
Browse files Browse the repository at this point in the history
  • Loading branch information
Jontes-Tech committed Feb 20, 2024
1 parent 8afb46c commit c87ab2c
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 41 deletions.
127 changes: 100 additions & 27 deletions app/src/layout/header/search/ResponsiveSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { MagnifyingGlassSVG } from '@ensdomains/thorin';
import clsx from 'clsx';
import { useState } from 'react';
import { useEffect, useRef, useState } from 'react';
import { FiLoader } from 'react-icons/fi';
import useSWR from 'swr';

Expand All @@ -11,7 +11,6 @@ import { SearchResults } from './SearchResults';

export const ResponsiveSearch = () => {
const [tag, setTag] = useState('All');

const [search, setSearch] = useState('');
const { data, error, isLoading, isValidating } = useSWR(
{ search, tag },
Expand All @@ -20,22 +19,99 @@ export const ResponsiveSearch = () => {
keepPreviousData: true,
}
);
const [select, setSelect] = useState(-1);
const [select, setSelect] = useState(-2);

const tags = [
'All',
'Intro',
'Using ENS',
'Smart Contracts',
'Governance',
'Improvement Proposals',
];

useEffect(() => {
if (select !== -1) return;

const element = document.querySelector(
'.filter-selected'
) as HTMLElement;

if (element) {
element.focus();
}
}, [select]);
const showSearch = search.length > 0 && data;

const selectReference = useRef(select);

selectReference.current = select;

const tagReference = useRef(tag);

tagReference.current = tag;

useEffect(() => {
const thateventlistener = (event) => {
if (selectReference.current !== -1) return;

const index = tags.indexOf(tagReference.current);

switch (event.key) {
case 'ArrowRight': {
const realIndex = Math.min(index + 1, tags.length - 1);

event.preventDefault();
// Increment the index, except if it's the last element
setTag(tags[realIndex]);
const element = document.querySelectorAll('.filter-tag')[
realIndex
] as HTMLElement;

if (element) {
element.focus();
}

break;
}
case 'ArrowLeft': {
const realIndex = Math.max(index - 1, 0);

event.preventDefault();
setTag(tags[realIndex]);
const element = document.querySelectorAll('.filter-tag')[
realIndex
] as HTMLElement;

if (element) {
element.focus();
}

break;
}
}
};

document.addEventListener('keydown', thateventlistener);

return () => {
document.removeEventListener('keydown', thateventlistener);
};
}, []);

return (
<div
id="searchbar"
className="w-full rounded-2xl bg-ens-light-background-primary text-[#18181b] dark:bg-ens-dark-background-primary dark:text-white"
className="bg-ens-light-background-primary dark:bg-ens-dark-background-primary w-full rounded-2xl text-[#18181b] dark:text-white"
>
<div className="space-y-3 p-4">
<div className="relative z-10">
<input
type="text"
onClick={() => {
setSelect(-1);
setSelect(-2);
}}
className="w-full rounded-xl border border-ens-light-border py-2 pl-10 text-xl outline-ens-dark-blue-primary focus:outline-ens-light-blue-primary dark:border-ens-dark-border"
className="border-ens-light-border outline-ens-dark-blue-primary focus:outline-ens-light-blue-primary dark:border-ens-dark-border w-full rounded-xl border py-2 pl-10 text-xl"
placeholder="Search Content..."
// eslint-disable-next-line jsx-a11y/no-autofocus
autoFocus={true}
Expand Down Expand Up @@ -65,27 +141,24 @@ export const ResponsiveSearch = () => {
</div>
<div className="overflow-x-auto">
<div className="flex w-fit gap-2 whitespace-nowrap">
{[
'All',
'Intro',
'Using ENS',
'Smart Contracts',
'Governance',
'Improvement Proposals',
].map((item, _index) => (
<button
className={clsx(
'tag',
tag === item ? 'tag-blue' : 'tag-grey'
)}
key={_index}
onClick={() => {
setTag(item);
}}
>
{item}
</button>
))}
{data?.hits?.length > 0 &&
search !== '' &&
tags.map((item, _index) => (
<button
className={clsx(
'tag filter-tag',
tag === item
? 'tag-blue filter-selected'
: 'tag-grey'
)}
key={_index}
onClick={() => {
setTag(item);
}}
>
{item}
</button>
))}
</div>
</div>
</div>
Expand Down
31 changes: 17 additions & 14 deletions app/src/layout/header/search/SearchResults.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client';
import clsx from 'clsx';
import Link from 'next/link';
import { FC, useEffect } from 'react';
import { FC, useEffect, useRef } from 'react';

import { SearchResult } from './types/result';

Expand All @@ -10,25 +10,32 @@ export const SearchResults: FC<{
select: any;
setSelect: any;
}> = ({ data, select, setSelect }) => {
const dataReference = useRef(data);

dataReference.current = data;

useEffect(() => {
const thateventlistener = (event) => {
if (!data?.hits?.length) {
if (!dataReference.current?.hits?.length) {
return;
}

switch (event.key) {
case 'ArrowDown': {
event.preventDefault();
setSelect((select) => {
return Math.min(select + 1, data.hits.length - 1);
return Math.min(
select + 1,
dataReference.current?.hits.length - 1
);
});

break;
}
case 'ArrowUp': {
event.preventDefault();
setSelect((select) => {
return Math.max(select - 1, -1);
return Math.max(select - 1, -2);
});

break;
Expand All @@ -47,15 +54,15 @@ export const SearchResults: FC<{
}, []);

useEffect(() => {
if (select !== -1) {
if (select !== -2 && select !== -1) {
const element = document.querySelector(
'#search-result-link-' + select
);

if (element instanceof HTMLElement) {
element.focus();
}
} else {
} else if (select === -2) {
const element = document.querySelector('#search-input');

if (element instanceof HTMLElement) {
Expand All @@ -64,24 +71,20 @@ export const SearchResults: FC<{
}
}, [select]);

useEffect(() => {
setSelect(-1);
}, [data.hits]);

return (
<>
<div className="w-full">
{!data.hits || data.hits.length === 0 ? (
<div className="flex w-full flex-col items-center py-8 text-center text-ens-light-text-primary dark:bg-ens-dark-grey-surface dark:text-ens-dark-text-primary">
<div className="text-ens-light-text-primary dark:bg-ens-dark-grey-surface dark:text-ens-dark-text-primary flex w-full flex-col items-center rounded-b-xl py-8 text-center">
<div className="text-4xl">🤷‍♀️</div>
<div className="">No results found</div>
<div className="text-sm">Try a different search</div>
</div>
) : (
<ul className="border-t border-t-ens-light-border dark:border-t-ens-dark-border">
<ul className="border-t-ens-light-border dark:border-t-ens-dark-border border-t">
{data.hits.map((hit, index) => (
<li
className="hlem outline-0 focus-within:bg-ens-light-background-secondary hover:bg-ens-light-background-secondary focus-within:dark:bg-ens-dark-background-secondary hover:dark:bg-ens-dark-background-secondary"
className="hlem focus-within:bg-ens-light-background-secondary hover:bg-ens-light-background-secondary focus-within:dark:bg-ens-dark-background-secondary hover:dark:bg-ens-dark-background-secondary outline-0"
id={'search-result-' + index}
key={hit.slug}
>
Expand All @@ -98,7 +101,7 @@ export const SearchResults: FC<{
}}
href={'/' + hit.slug}
id={'search-result-link-' + index}
className="z-10 flex w-full p-4 outline-ens-dark-blue-primary focus:outline-ens-light-blue-primary"
className="outline-ens-dark-blue-primary focus:outline-ens-light-blue-primary z-10 flex w-full p-4"
>
<span className="grow overflow-hidden">
<span className="w-full truncate font-bold">
Expand Down

0 comments on commit c87ab2c

Please sign in to comment.