Skip to content

Commit

Permalink
site: implement flexsearch (#36)
Browse files Browse the repository at this point in the history
* site: implement flexsearch

* site: add no search results banner

* site: work around empty searchParams Next.js bug?
related vercel/next.js#53543
  • Loading branch information
luwes authored Jun 28, 2024
1 parent 34bc78d commit caac745
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 16 deletions.
7 changes: 7 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 21 additions & 7 deletions site/app/(home)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ export default async function Home({ searchParams }: HomeProps) {
</Link>
.
</Hero>
<div className="relative border-y -my-1px grid grid-cols-xs sm:grid-cols-sm lg:grid-cols-lg xl:grid-cols-xl bg-putty-light border-ctx-gray text-black set-bg-ctx-putty-light set-border-ctx-gray">
<div className="relative flex-1 border-y -my-1px grid grid-cols-xs sm:grid-cols-sm lg:grid-cols-lg xl:grid-cols-xl bg-putty-light border-ctx-gray text-black set-bg-ctx-putty-light set-border-ctx-gray">
<div className="col-start-2 col-end-3 border-x border-ctx-gray">
<div className="-m-0.5px grid grid-cols-1 lg:grid-cols-3">
<div className="border-ctx border -m-0.5px flex flex-col">
<div className="-m-0.5px grid grid-cols-1 lg:grid-cols-3 h-full">
<div className="border-ctx border border-b-0 -m-0.5px flex flex-col">
<div className="border-ctx border -m-0.5px font-mono text-sm leading-mono font-normal uppercase -mx-1px -mt-1px h-3 p-1 flex items-center justify-center text-center">
Filter themes
</div>
Expand Down Expand Up @@ -57,10 +57,24 @@ export default async function Home({ searchParams }: HomeProps) {
))}
</div>
</div>
<div className="lg:col-span-2 grid">
{themes.map((theme, index) => (
<ThemePreview priority={index === 0} key={`theme-${theme._meta.path}`} theme={theme} />
))}
<div className="lg:col-span-2 grid h-min">
{themes.length ? (
themes.map((theme, index) => (
<ThemePreview
priority={index === 0}
key={`theme-${theme._meta.path}`}
theme={theme}
/>
))
) : (
<div className="-m-0.5px grid flex flex-col items-center">
<div className="p-1 md:p-2 lg:p-4 text-balance">
<h3 className="font-body text-xl md:text-3xl leading-heading font-bold normal-case pb-1 text-center lg:text-left">
<p>Aw snap! No search results were found.</p>
</h3>
</div>
</div>
)}
</div>
</div>
</div>
Expand Down
7 changes: 6 additions & 1 deletion site/app/_components/Grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ type GridProps = {
export default function Grid({ className, children }: GridProps) {
return (
<>
<div className={clsx('relative flex-1 border-y -my-1px grid grid-cols-xs sm:grid-cols-sm lg:grid-cols-lg xl:grid-cols-xl bg-putty-light border-ctx-gray text-black set-bg-ctx-putty-light set-border-ctx-gray', className)}>
<div
className={clsx(
'relative border-y -my-1px grid grid-cols-xs sm:grid-cols-sm lg:grid-cols-lg xl:grid-cols-xl bg-putty-light border-ctx-gray text-black set-bg-ctx-putty-light set-border-ctx-gray',
className
)}
>
<div className="col-start-2 col-end-3 border-x border-ctx-gray">
<div className="gap-2 lg:gap-3 items-center py-2 px-1 md:p-2 lg:py-3 lg:px-3">
<div className="block border-ctx-gray bg-putty-light [&amp;>*]:set-border-ctx-gray [&amp;>*]:set-bg-ctx-putty-light text-black">
Expand Down
17 changes: 14 additions & 3 deletions site/app/_components/Search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ export default function Search() {
if (term) {
params.set('search', term);
} else {
params.delete('search');
// This is a workaround for a bug where the page without a search query
// would not trigger a RSC update.
// params.delete('search');
params.set('search', term);
}
replace(`${pathname}?${params.toString()}`, { scroll: false });
};
Expand All @@ -37,7 +40,12 @@ export default function Search() {
defaultValue={search}
/>
</span>
<span className={clsx(search && 'hidden', 'absolute right-2 top-1/2 -translate-y-1/2 cursor-pointer')}>
<span
className={clsx(
search && 'hidden',
'absolute right-2 top-1/2 -translate-y-1/2 cursor-pointer'
)}
>
<svg
role="img"
xmlns="http://www.w3.org/2000/svg"
Expand All @@ -62,7 +70,10 @@ export default function Search() {
</svg>
</span>
<button
className={clsx(!search && 'hidden', 'absolute top-1/2 -translate-y-1/2 cursor-pointer right-2')}
className={clsx(
!search && 'hidden',
'absolute top-1/2 -translate-y-1/2 cursor-pointer right-2'
)}
onClick={() => {
if (!inputRef.current) return;
inputRef.current.focus();
Expand Down
18 changes: 14 additions & 4 deletions site/app/_utils/content.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import deepMerge from 'deepmerge';
import { allThemes, allPlayers, allFeatures, allFrameworks } from 'content-collections';
import { Meta } from '@content-collections/core';
import flexsearch from 'flexsearch';

const { Document } = flexsearch;

const allCollections = {
themes: allThemes,
Expand Down Expand Up @@ -57,16 +60,23 @@ async function filterCollection<T extends { _meta: Meta }>(

if (searchParams.search) {
const search = `${searchParams.search}`.toLowerCase();
return collection.filter((item: any) => {
return (
item.title.toLowerCase().includes(search) || item.description.toLowerCase().includes(search)
);
const index = new Document({
tokenize: 'forward',
document: {
id: '_meta:path',
index: ['title', 'description', 'author'],
},
});
collection.forEach((item) => index.add(item));
const results = index.search(search);
const ids = [...new Set(results.flatMap(({ result }) => result))];
return ids.map((id) => collection.find((item) => item._meta.path === id));
}

for (let [tagGroup, selectedTags] of Object.entries(searchParams)) {
const selectedTagsArray = Array.isArray(selectedTags) ? selectedTags : [selectedTags];
collection = collection.filter((item: any) => {
if (!item.tagGroups[tagGroup]) return true;
return selectedTagsArray.some((tag: string) =>
includesIgnoreCase(item.tagGroups[tagGroup], tag)
);
Expand Down
2 changes: 1 addition & 1 deletion site/app/about/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Grid from '../_components/Grid';
export default function About() {
return (
<>
<Grid>
<Grid className="flex-1">
<h1 className="text-3xl font-bold mb-0.5">About</h1>
<p className="text-md mb-0.5 md:mr-8">
Player.style is a platform for creating and sharing media player themes.
Expand Down
1 change: 1 addition & 0 deletions site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"@next/mdx": "^14.2.3",
"clsx": "^2.1.1",
"deepmerge": "^4.3.1",
"flexsearch": "^0.7.43",
"hls-video-element": "^1.2.5",
"media-chrome": "^3.2.3",
"next": "14.2.3",
Expand Down
1 change: 1 addition & 0 deletions site/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"target": "esnext",
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
Expand Down

0 comments on commit caac745

Please sign in to comment.