Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨Search page #2549

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ export const DocsNavigationList = ({ navItems }: DocsNavProps) => {
return (
<>
<DocsNavigationContainer ref={navListElem}>
{navItems.map((categoryData) => (
{navItems?.map((categoryData) => (
<NavLevel
key={
'mobile-' +
Expand Down
2 changes: 0 additions & 2 deletions components/DocumentationNavigation/VersionSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ const SelectWrapper = styled.div`

.dropdown-button {
font-size: 0.875rem;
margin-right: 2.5rem;
padding: 0.375rem 0.75rem;
background-color: white;
border: 1px solid var(--color-grey-1);
Expand All @@ -111,7 +110,6 @@ const DropdownList = styled.ul`
background-color: white;
border: 1px solid var(--color-grey-1);
border-radius: 0.375rem;
margin-top: 2rem;
padding: 0.5rem 0;
z-index: 10;

Expand Down
191 changes: 191 additions & 0 deletions components/docsSearch/SearchComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
import Link from "next/link";
import { useState, useEffect, useRef } from "react";
import { fetchAlgoliaSearchResults } from "utils/new-search";

export const SearchHeader = ({ query }: { query: string }) => {
const [isFilterOpen, setIsFilterOpen] = useState(false);
const [isSortOpen, setIsSortOpen] = useState(false);

const filterOptions = ['FilterOp1', 'FilterOp2', 'FilterOp3'];
const sortOptions = ['Relevance', 'Newest First', 'Oldest First'];

const toggleFilterDropdown = () => {
setIsFilterOpen(!isFilterOpen);
setIsSortOpen(false);
};

const toggleSortDropdown = () => {
setIsSortOpen(!isSortOpen);
setIsFilterOpen(false);
};

return (
<div className="flex justify-between relative pt-4">
<div className="font-tuner text-3xl bg-gradient-to-br from-orange-300 via-orange-400 to-orange-600 bg-clip-text text-transparent">
Results for "{query}"
</div>
<div className="flex text-end gap-6 items-center">
{/* Filter Button */}
<div className="relative">
{/* TODO: Implement Feature and Sort buttons - https://github.com/tinacms/tina.io/issues/2550 */}
{/* <button
className="flex items-center gap-1 text-sm"
onClick={toggleFilterDropdown}
>
<MdFilterAlt size={16} /> FILTER
</button> */}
{isFilterOpen && (
<div className="absolute right-0 top-full bg-white shadow-xl rounded-md p-2 px-4 transition ease-out duration-150 z-10 w-40">
{filterOptions.map((option) => (
<div
key={option}
className="py-2 text-left cursor-pointer font-light"
onClick={() => {

setIsFilterOpen(false);
}}
>
{option}
</div>
))}
</div>
)}
</div>

{/* Sort Button */}
{/* <div className="relative">
<button
className="flex items-center gap-1 text-sm"
onClick={toggleSortDropdown}
>
<MdSort size={16} /> SORT
</button>
{isSortOpen && (
<div className="absolute right-0 top-full bg-white shadow-xl rounded-md p-2 px-4 transition ease-out duration-150 z-10 w-40">
{sortOptions.map((option) => (
<div
key={option}
className="py-2 cursor-pointer font-light text-left"
onClick={() => {

setIsSortOpen(false);
}}
>
{option}
</div>
))}
</div>
)}
</div> */}
</div>
</div>
);
};

export const SearchTabs = ({ query }: { query: string }) => {
const [activeTab, setActiveTab] = useState('DOCS');
const [algoliaSearchResults, setAlgoliaSearchResults] = useState<any>(null);
const [isLoading, setIsLoading] = useState(false);

useEffect(() => {
const fetchResults = async () => {
setIsLoading(true);
setAlgoliaSearchResults(null);
if (query) {
const results = await fetchAlgoliaSearchResults(query);
setAlgoliaSearchResults(results);
}
setIsLoading(false);
};

fetchResults();
}, [query]);

const tabRefs = useRef<(HTMLButtonElement | null)[]>([]);
const activeTabIndex = activeTab === 'DOCS' ? 0 : 1;
const activeTabElement = tabRefs.current[activeTabIndex];
const left = activeTabElement?.offsetLeft || 0;
const width = (activeTabElement?.offsetWidth || 0) + 30;

const numberOfResults =
(algoliaSearchResults?.docs?.count + algoliaSearchResults?.blogs?.count) || 0;

return (
<div className="pt-6 w-full">
<div className="max-w-screen-xl mx-auto pb-2">
<div className="flex justify-between items-center">
{/* Navigation Buttons */}
<nav className="relative flex gap-16 px-4">
<button
ref={(el) => (tabRefs.current[0] = el)}
className={`font-inter text-lg ${
activeTab === 'DOCS' ? 'text-blue-800' : 'text-gray-500'
}`}
onClick={() => setActiveTab('DOCS')}
>
DOCS ({algoliaSearchResults?.docs?.count})
</button>
<button
ref={(el) => (tabRefs.current[1] = el)}
className={`font-inter text-lg ${
activeTab === 'BLOG' ? 'text-blue-800' : 'text-gray-500'
}`}
onClick={() => setActiveTab('BLOG')}
>
BLOGS ({algoliaSearchResults?.blogs?.count})
</button>

{/* Blue moving underline */}
<div
className="absolute -bottom-2 h-0.5 bg-blue-800 transition-all duration-300 ease-in-out"
style={{
left: `${left}px`,
width: `${width}px`,
transform: 'translateX(-15px)', //To make sure the blue line is in the middle of the component we minus 1/2 of the width of the blue line
}}
/>
</nav>

{/* Search Results Count */}
<div className="ml-auto text-end text-lg font-inter text-blue-800">
{numberOfResults}{' '}
Results
</div>
</div>
{isLoading && (
<div className="pt-10 text-2xl bg-gradient-to-br from-orange-300 via-orange-400 to-orange-600 bg-clip-text text-transparent font-tuner">
Gathering all the Llamas...
</div>
)}
<SearchBody results={algoliaSearchResults} activeItem={activeTab} />
{(numberOfResults == 0 && isLoading==false) && <div className='font-inter font-semibold text-gray-500 text-xl'>No Results Found...</div>}
</div>
</div>
);
};

export const SearchBody = ({
results,
activeItem,
}: {
results: any;
activeItem: string;
}) => {
const bodyItem = activeItem === 'DOCS' ? results?.docs : results?.blogs;
return (
<div className="py-10">
{bodyItem?.results.map((item: any) => (
<div key={item.objectID} className="py-4 px-4 border-b group">
<Link href={`/${activeItem.toLowerCase()}/${item.slug}`}>
<h2 className="text-xl font-inter font-semibold bg-gradient-to-br from-blue-600/80 via-blue-800/80 to-blue-1000 bg-clip-text text-transparent group-hover:from-orange-300 group-hover:via-orange-400 group-hover:to-orange-600 break-words">
{item.title}
</h2>
<p className="text-gray-600 group-hover:text-gray-800 text-sm font-light line-clamp-3 break-words">
{item.excerpt}
</p>
</Link>
</div>
))}
</div>
);
};
Loading