refactor: Add tag filtering functionality to theme search

This commit is contained in:
Mauro Balades
2024-08-22 21:36:01 +02:00
parent 30cde8f559
commit 7f74a62982
3 changed files with 55 additions and 26 deletions

View File

@@ -7,6 +7,7 @@ import { Button } from "./ui/button";
export default function MarketplacePage() { export default function MarketplacePage() {
const [searchInput, setSearchInput] = React.useState(""); const [searchInput, setSearchInput] = React.useState("");
const [tags, setTags] = React.useState<string[]>(["all"]);
const [themes, setThemes] = React.useState<ZenTheme[]>([]); const [themes, setThemes] = React.useState<ZenTheme[]>([]);
React.useEffect(() => { React.useEffect(() => {
@@ -18,11 +19,11 @@ export default function MarketplacePage() {
<div className="mx-auto w-full text-center border-b pt-48 pb-24 mb-12 bg-gradient-to-r from-[#f6cfbe] to-[#b9dcf2] dark:from-[#0d1117] dark:to-[#0d1117]"> <div className="mx-auto w-full text-center border-b pt-48 pb-24 mb-12 bg-gradient-to-r from-[#f6cfbe] to-[#b9dcf2] dark:from-[#0d1117] dark:to-[#0d1117]">
<div className="w-full lg:w-1/2 xl:w-1/2 mx-auto px-2 lg:px-none"> <div className="w-full lg:w-1/2 xl:w-1/2 mx-auto px-2 lg:px-none">
<h1 className="text-4xl lg:text-7xl font-bold">Themes Store</h1> <h1 className="text-4xl lg:text-7xl font-bold">Themes Store</h1>
<ThemesSearch input={searchInput} setInput={setSearchInput} /> <ThemesSearch input={searchInput} setInput={setSearchInput} tags={tags} setTags={setTags} />
</div> </div>
</div> </div>
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4 gap-8 mt-10 w-full lg:w-1/2 xl:w-2/3 2xl:w-3/4"> <div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4 gap-8 mt-10 w-full lg:w-1/2 xl:w-2/3 2xl:w-3/4">
{getThemesFromSearch(themes, searchInput).map((theme) => ( {getThemesFromSearch(themes, searchInput, tags).map((theme) => (
<ThemeCard key={theme.name} theme={theme} /> <ThemeCard key={theme.name} theme={theme} />
))} ))}
</div> </div>

View File

@@ -1,30 +1,51 @@
import { SearchIcon } from "lucide-react"; import { SearchIcon } from "lucide-react";
import { Button } from "./ui/button"; import { Button } from "./ui/button";
import { ny } from "@/lib/utils";
const TAGS = [
"all",
"color-scheme",
"utility",
];
export default function ThemesSearch({ export default function ThemesSearch({
input, setInput input, setInput, tags, setTags
}: { }: {
input: string; input: string;
setInput: (input: string) => void; setInput: (input: string) => void;
tags: string[];
setTags: (tags: string[]) => void;
}) { }) {
return ( return (
<div className="flex w-full p-2 bg-black/10 dark:bg-muted/50 rounded-full overflow-hidden mt-10 items-center border border-black dark:border-muted"> <>
<SearchIcon className="w-6 h-6 mx-4 text-black dark:text-white" /> <div className="flex w-full p-2 bg-black/10 dark:bg-muted/50 rounded-full overflow-hidden mt-10 items-center border border-black dark:border-muted">
<input <SearchIcon className="w-6 h-6 mx-4 text-black dark:text-white" />
type="text" <input
value={input} type="text"
onChange={(e) => setInput(e.target.value)} value={input}
placeholder="Search themes" onChange={(e) => setInput(e.target.value)}
className="w-full bg-transparent border-none focus:outline-none focus:border-none focus:ring-0 dark:text-white text-black" placeholder="Search themes"
/> className="w-full bg-transparent border-none focus:outline-none focus:border-none focus:ring-0 dark:text-white text-black"
<Button />
onClick={() => window.open("https://docs.zen-browser.app/themes-store/themes-marketplace-submission-guidelines#themes-store-submission-guidelines", "_blank")} <Button
className="text-muted rounded-full rounded-r-none hidden md:block" onClick={() => window.open("https://docs.zen-browser.app/themes-store/themes-marketplace-submission-guidelines#themes-store-submission-guidelines", "_blank")}
>Submit a theme</Button> className="text-muted rounded-full rounded-r-none hidden md:block"
<Button >Submit a theme</Button>
onClick={() => window.open("/create-theme", "_self")} <Button
className="text-muted rounded-full rounded-l-none border-l border-black dark:border-none hidden md:block" onClick={() => window.open("/create-theme", "_self")}
>Create your theme</Button> className="text-muted rounded-full rounded-l-none border-l border-black dark:border-none hidden md:block"
</div> >Create your theme</Button>
</div>
<div className="flex flex-wrap gap-2 mt-4">
{TAGS.map((tag) => (
<Button
variant="ghost"
key={tag}
onClick={() => setTags([tag])}
className={ny(`!rounded-full px-5 ${tags.includes(tag) ? "bg-black dark:bg-white text-white dark:text-black" : ""}`)}
>{tag}</Button>
))}
</div>
</>
); );
} }

View File

@@ -7,9 +7,8 @@ export interface ZenTheme {
id: string id: string
homepage?: string homepage?: string
readme: string readme: string
preferences: { preferences?: string
[key: string]: string isColorTheme: boolean
},
author: string author: string
} }
@@ -28,8 +27,16 @@ export async function getAllThemes() {
return themesArray; return themesArray;
} }
export function getThemesFromSearch(themes: ZenTheme[], query: string): ZenTheme[] { export function getThemesFromSearch(themes: ZenTheme[], query: string, tags: string[]): ZenTheme[] {
return themes.filter((theme) => theme.name.toLowerCase().includes(query.toLowerCase())); let filtered = themes.filter((theme) => theme.name.toLowerCase().includes(query.toLowerCase()));
if (tags.includes("all")) return filtered;
const isSearchingForColorScheme = tags.includes("color-scheme");
const isSearchingForUtility = !isSearchingForColorScheme && tags.includes("utility");
return filtered.filter((theme) => {
if (isSearchingForColorScheme && theme.isColorTheme) return true;
if (isSearchingForUtility && !theme.isColorTheme) return true;
return false;
});
} }
export async function getThemeFromId(id: string) { export async function getThemeFromId(id: string) {